3 var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
5 var check = function (it) {
6 return it && it.Math == Math && it;
9 // https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
11 // eslint-disable-next-line es/no-global-this -- safe
12 check(typeof globalThis == 'object' && globalThis) ||
13 check(typeof window == 'object' && window) ||
14 // eslint-disable-next-line no-restricted-globals -- safe
15 check(typeof self == 'object' && self) ||
16 check(typeof commonjsGlobal == 'object' && commonjsGlobal) ||
17 // eslint-disable-next-line no-new-func -- fallback
18 (function () { return this; })() || Function('return this')();
20 var objectGetOwnPropertyDescriptor = {};
22 var fails$N = function (exec) {
30 var fails$M = fails$N;
32 // Detect IE8's incomplete defineProperty implementation
33 var descriptors = !fails$M(function () {
34 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
35 return Object.defineProperty({}, 1, { get: function () { return 7; } })[1] != 7;
38 var objectPropertyIsEnumerable = {};
40 var $propertyIsEnumerable$1 = {}.propertyIsEnumerable;
41 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
42 var getOwnPropertyDescriptor$5 = Object.getOwnPropertyDescriptor;
45 var NASHORN_BUG = getOwnPropertyDescriptor$5 && !$propertyIsEnumerable$1.call({ 1: 2 }, 1);
47 // `Object.prototype.propertyIsEnumerable` method implementation
48 // https://tc39.es/ecma262/#sec-object.prototype.propertyisenumerable
49 objectPropertyIsEnumerable.f = NASHORN_BUG ? function propertyIsEnumerable(V) {
50 var descriptor = getOwnPropertyDescriptor$5(this, V);
51 return !!descriptor && descriptor.enumerable;
52 } : $propertyIsEnumerable$1;
54 var createPropertyDescriptor$7 = function (bitmap, value) {
56 enumerable: !(bitmap & 1),
57 configurable: !(bitmap & 2),
58 writable: !(bitmap & 4),
63 var toString$2 = {}.toString;
65 var classofRaw$1 = function (it) {
66 return toString$2.call(it).slice(8, -1);
69 var fails$L = fails$N;
70 var classof$c = classofRaw$1;
72 var split$1 = ''.split;
74 // fallback for non-array-like ES3 and non-enumerable old V8 strings
75 var indexedObject = fails$L(function () {
76 // throws an error in rhino, see https://github.com/mozilla/rhino/issues/346
77 // eslint-disable-next-line no-prototype-builtins -- safe
78 return !Object('z').propertyIsEnumerable(0);
80 return classof$c(it) == 'String' ? split$1.call(it, '') : Object(it);
83 // `RequireObjectCoercible` abstract operation
84 // https://tc39.es/ecma262/#sec-requireobjectcoercible
85 var requireObjectCoercible$e = function (it) {
86 if (it == undefined) throw TypeError("Can't call method on " + it);
90 // toObject with fallback for non-array-like ES3 strings
91 var IndexedObject$4 = indexedObject;
92 var requireObjectCoercible$d = requireObjectCoercible$e;
94 var toIndexedObject$b = function (it) {
95 return IndexedObject$4(requireObjectCoercible$d(it));
98 var isObject$r = function (it) {
99 return typeof it === 'object' ? it !== null : typeof it === 'function';
102 var isObject$q = isObject$r;
104 // `ToPrimitive` abstract operation
105 // https://tc39.es/ecma262/#sec-toprimitive
106 // instead of the ES6 spec version, we didn't implement @@toPrimitive case
107 // and the second argument - flag - preferred type is a string
108 var toPrimitive$7 = function (input, PREFERRED_STRING) {
109 if (!isObject$q(input)) return input;
111 if (PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$q(val = fn.call(input))) return val;
112 if (typeof (fn = input.valueOf) == 'function' && !isObject$q(val = fn.call(input))) return val;
113 if (!PREFERRED_STRING && typeof (fn = input.toString) == 'function' && !isObject$q(val = fn.call(input))) return val;
114 throw TypeError("Can't convert object to primitive value");
117 var requireObjectCoercible$c = requireObjectCoercible$e;
119 // `ToObject` abstract operation
120 // https://tc39.es/ecma262/#sec-toobject
121 var toObject$i = function (argument) {
122 return Object(requireObjectCoercible$c(argument));
125 var toObject$h = toObject$i;
127 var hasOwnProperty$3 = {}.hasOwnProperty;
129 var has$j = Object.hasOwn || function hasOwn(it, key) {
130 return hasOwnProperty$3.call(toObject$h(it), key);
133 var global$E = global$F;
134 var isObject$p = isObject$r;
136 var document$3 = global$E.document;
137 // typeof document.createElement is 'object' in old IE
138 var EXISTS = isObject$p(document$3) && isObject$p(document$3.createElement);
140 var documentCreateElement$1 = function (it) {
141 return EXISTS ? document$3.createElement(it) : {};
144 var DESCRIPTORS$m = descriptors;
145 var fails$K = fails$N;
146 var createElement$1 = documentCreateElement$1;
148 // Thank's IE8 for his funny defineProperty
149 var ie8DomDefine = !DESCRIPTORS$m && !fails$K(function () {
150 // eslint-disable-next-line es/no-object-defineproperty -- requied for testing
151 return Object.defineProperty(createElement$1('div'), 'a', {
152 get: function () { return 7; }
156 var DESCRIPTORS$l = descriptors;
157 var propertyIsEnumerableModule$2 = objectPropertyIsEnumerable;
158 var createPropertyDescriptor$6 = createPropertyDescriptor$7;
159 var toIndexedObject$a = toIndexedObject$b;
160 var toPrimitive$6 = toPrimitive$7;
162 var IE8_DOM_DEFINE$1 = ie8DomDefine;
164 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
165 var $getOwnPropertyDescriptor$1 = Object.getOwnPropertyDescriptor;
167 // `Object.getOwnPropertyDescriptor` method
168 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
169 objectGetOwnPropertyDescriptor.f = DESCRIPTORS$l ? $getOwnPropertyDescriptor$1 : function getOwnPropertyDescriptor(O, P) {
170 O = toIndexedObject$a(O);
171 P = toPrimitive$6(P, true);
172 if (IE8_DOM_DEFINE$1) try {
173 return $getOwnPropertyDescriptor$1(O, P);
174 } catch (error) { /* empty */ }
175 if (has$i(O, P)) return createPropertyDescriptor$6(!propertyIsEnumerableModule$2.f.call(O, P), O[P]);
178 var objectDefineProperty = {};
180 var isObject$o = isObject$r;
182 var anObject$m = function (it) {
183 if (!isObject$o(it)) {
184 throw TypeError(String(it) + ' is not an object');
188 var DESCRIPTORS$k = descriptors;
189 var IE8_DOM_DEFINE = ie8DomDefine;
190 var anObject$l = anObject$m;
191 var toPrimitive$5 = toPrimitive$7;
193 // eslint-disable-next-line es/no-object-defineproperty -- safe
194 var $defineProperty$1 = Object.defineProperty;
196 // `Object.defineProperty` method
197 // https://tc39.es/ecma262/#sec-object.defineproperty
198 objectDefineProperty.f = DESCRIPTORS$k ? $defineProperty$1 : function defineProperty(O, P, Attributes) {
200 P = toPrimitive$5(P, true);
201 anObject$l(Attributes);
202 if (IE8_DOM_DEFINE) try {
203 return $defineProperty$1(O, P, Attributes);
204 } catch (error) { /* empty */ }
205 if ('get' in Attributes || 'set' in Attributes) throw TypeError('Accessors not supported');
206 if ('value' in Attributes) O[P] = Attributes.value;
210 var DESCRIPTORS$j = descriptors;
211 var definePropertyModule$7 = objectDefineProperty;
212 var createPropertyDescriptor$5 = createPropertyDescriptor$7;
214 var createNonEnumerableProperty$e = DESCRIPTORS$j ? function (object, key, value) {
215 return definePropertyModule$7.f(object, key, createPropertyDescriptor$5(1, value));
216 } : function (object, key, value) {
221 var redefine$g = {exports: {}};
223 var global$D = global$F;
224 var createNonEnumerableProperty$d = createNonEnumerableProperty$e;
226 var setGlobal$3 = function (key, value) {
228 createNonEnumerableProperty$d(global$D, key, value);
230 global$D[key] = value;
234 var global$C = global$F;
235 var setGlobal$2 = setGlobal$3;
237 var SHARED = '__core-js_shared__';
238 var store$4 = global$C[SHARED] || setGlobal$2(SHARED, {});
240 var sharedStore = store$4;
242 var store$3 = sharedStore;
244 var functionToString = Function.toString;
246 // this helper broken in `core-js@3.4.1-3.4.4`, so we can't use `shared` helper
247 if (typeof store$3.inspectSource != 'function') {
248 store$3.inspectSource = function (it) {
249 return functionToString.call(it);
253 var inspectSource$3 = store$3.inspectSource;
255 var global$B = global$F;
256 var inspectSource$2 = inspectSource$3;
258 var WeakMap$1 = global$B.WeakMap;
260 var nativeWeakMap = typeof WeakMap$1 === 'function' && /native code/.test(inspectSource$2(WeakMap$1));
262 var shared$5 = {exports: {}};
266 var store$2 = sharedStore;
268 (shared$5.exports = function (key, value) {
269 return store$2[key] || (store$2[key] = value !== undefined ? value : {});
270 })('versions', []).push({
273 copyright: '© 2021 Denis Pushkarev (zloirock.ru)'
277 var postfix = Math.random();
279 var uid$5 = function (key) {
280 return 'Symbol(' + String(key === undefined ? '' : key) + ')_' + (++id$2 + postfix).toString(36);
283 var shared$4 = shared$5.exports;
286 var keys$3 = shared$4('keys');
288 var sharedKey$4 = function (key) {
289 return keys$3[key] || (keys$3[key] = uid$4(key));
292 var hiddenKeys$6 = {};
294 var NATIVE_WEAK_MAP = nativeWeakMap;
295 var global$A = global$F;
296 var isObject$n = isObject$r;
297 var createNonEnumerableProperty$c = createNonEnumerableProperty$e;
298 var objectHas = has$j;
299 var shared$3 = sharedStore;
300 var sharedKey$3 = sharedKey$4;
301 var hiddenKeys$5 = hiddenKeys$6;
303 var OBJECT_ALREADY_INITIALIZED = 'Object already initialized';
304 var WeakMap = global$A.WeakMap;
305 var set$4, get$5, has$h;
307 var enforce = function (it) {
308 return has$h(it) ? get$5(it) : set$4(it, {});
311 var getterFor = function (TYPE) {
312 return function (it) {
314 if (!isObject$n(it) || (state = get$5(it)).type !== TYPE) {
315 throw TypeError('Incompatible receiver, ' + TYPE + ' required');
320 if (NATIVE_WEAK_MAP || shared$3.state) {
321 var store$1 = shared$3.state || (shared$3.state = new WeakMap());
322 var wmget = store$1.get;
323 var wmhas = store$1.has;
324 var wmset = store$1.set;
325 set$4 = function (it, metadata) {
326 if (wmhas.call(store$1, it)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
327 metadata.facade = it;
328 wmset.call(store$1, it, metadata);
331 get$5 = function (it) {
332 return wmget.call(store$1, it) || {};
334 has$h = function (it) {
335 return wmhas.call(store$1, it);
338 var STATE = sharedKey$3('state');
339 hiddenKeys$5[STATE] = true;
340 set$4 = function (it, metadata) {
341 if (objectHas(it, STATE)) throw new TypeError(OBJECT_ALREADY_INITIALIZED);
342 metadata.facade = it;
343 createNonEnumerableProperty$c(it, STATE, metadata);
346 get$5 = function (it) {
347 return objectHas(it, STATE) ? it[STATE] : {};
349 has$h = function (it) {
350 return objectHas(it, STATE);
354 var internalState = {
362 var global$z = global$F;
363 var createNonEnumerableProperty$b = createNonEnumerableProperty$e;
365 var setGlobal$1 = setGlobal$3;
366 var inspectSource$1 = inspectSource$3;
367 var InternalStateModule$9 = internalState;
369 var getInternalState$7 = InternalStateModule$9.get;
370 var enforceInternalState$1 = InternalStateModule$9.enforce;
371 var TEMPLATE = String(String).split('String');
373 (redefine$g.exports = function (O, key, value, options) {
374 var unsafe = options ? !!options.unsafe : false;
375 var simple = options ? !!options.enumerable : false;
376 var noTargetGet = options ? !!options.noTargetGet : false;
378 if (typeof value == 'function') {
379 if (typeof key == 'string' && !has$g(value, 'name')) {
380 createNonEnumerableProperty$b(value, 'name', key);
382 state = enforceInternalState$1(value);
384 state.source = TEMPLATE.join(typeof key == 'string' ? key : '');
387 if (O === global$z) {
388 if (simple) O[key] = value;
389 else setGlobal$1(key, value);
391 } else if (!unsafe) {
393 } else if (!noTargetGet && O[key]) {
396 if (simple) O[key] = value;
397 else createNonEnumerableProperty$b(O, key, value);
398 // add fake Function#toString for correct work wrapped methods / constructors with methods like LoDash isNative
399 })(Function.prototype, 'toString', function toString() {
400 return typeof this == 'function' && getInternalState$7(this).source || inspectSource$1(this);
403 var global$y = global$F;
405 var path$2 = global$y;
408 var global$x = global$F;
410 var aFunction$a = function (variable) {
411 return typeof variable == 'function' ? variable : undefined;
414 var getBuiltIn$9 = function (namespace, method) {
415 return arguments.length < 2 ? aFunction$a(path$1[namespace]) || aFunction$a(global$x[namespace])
416 : path$1[namespace] && path$1[namespace][method] || global$x[namespace] && global$x[namespace][method];
419 var objectGetOwnPropertyNames = {};
421 var ceil$1 = Math.ceil;
422 var floor$7 = Math.floor;
424 // `ToInteger` abstract operation
425 // https://tc39.es/ecma262/#sec-tointeger
426 var toInteger$b = function (argument) {
427 return isNaN(argument = +argument) ? 0 : (argument > 0 ? floor$7 : ceil$1)(argument);
430 var toInteger$a = toInteger$b;
432 var min$9 = Math.min;
434 // `ToLength` abstract operation
435 // https://tc39.es/ecma262/#sec-tolength
436 var toLength$q = function (argument) {
437 return argument > 0 ? min$9(toInteger$a(argument), 0x1FFFFFFFFFFFFF) : 0; // 2 ** 53 - 1 == 9007199254740991
440 var toInteger$9 = toInteger$b;
442 var max$4 = Math.max;
443 var min$8 = Math.min;
445 // Helper for a popular repeating case of the spec:
446 // Let integer be ? ToInteger(index).
447 // If integer < 0, let result be max((length + integer), 0); else let result be min(integer, length).
448 var toAbsoluteIndex$8 = function (index, length) {
449 var integer = toInteger$9(index);
450 return integer < 0 ? max$4(integer + length, 0) : min$8(integer, length);
453 var toIndexedObject$9 = toIndexedObject$b;
454 var toLength$p = toLength$q;
455 var toAbsoluteIndex$7 = toAbsoluteIndex$8;
457 // `Array.prototype.{ indexOf, includes }` methods implementation
458 var createMethod$6 = function (IS_INCLUDES) {
459 return function ($this, el, fromIndex) {
460 var O = toIndexedObject$9($this);
461 var length = toLength$p(O.length);
462 var index = toAbsoluteIndex$7(fromIndex, length);
464 // Array#includes uses SameValueZero equality algorithm
465 // eslint-disable-next-line no-self-compare -- NaN check
466 if (IS_INCLUDES && el != el) while (length > index) {
468 // eslint-disable-next-line no-self-compare -- NaN check
469 if (value != value) return true;
470 // Array#indexOf ignores holes, Array#includes - not
471 } else for (;length > index; index++) {
472 if ((IS_INCLUDES || index in O) && O[index] === el) return IS_INCLUDES || index || 0;
473 } return !IS_INCLUDES && -1;
477 var arrayIncludes = {
478 // `Array.prototype.includes` method
479 // https://tc39.es/ecma262/#sec-array.prototype.includes
480 includes: createMethod$6(true),
481 // `Array.prototype.indexOf` method
482 // https://tc39.es/ecma262/#sec-array.prototype.indexof
483 indexOf: createMethod$6(false)
487 var toIndexedObject$8 = toIndexedObject$b;
488 var indexOf = arrayIncludes.indexOf;
489 var hiddenKeys$4 = hiddenKeys$6;
491 var objectKeysInternal = function (object, names) {
492 var O = toIndexedObject$8(object);
496 for (key in O) !has$f(hiddenKeys$4, key) && has$f(O, key) && result.push(key);
497 // Don't enum bug & hidden keys
498 while (names.length > i) if (has$f(O, key = names[i++])) {
499 ~indexOf(result, key) || result.push(key);
504 // IE8- don't enum bug keys
505 var enumBugKeys$3 = [
509 'propertyIsEnumerable',
515 var internalObjectKeys$1 = objectKeysInternal;
516 var enumBugKeys$2 = enumBugKeys$3;
518 var hiddenKeys$3 = enumBugKeys$2.concat('length', 'prototype');
520 // `Object.getOwnPropertyNames` method
521 // https://tc39.es/ecma262/#sec-object.getownpropertynames
522 // eslint-disable-next-line es/no-object-getownpropertynames -- safe
523 objectGetOwnPropertyNames.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O) {
524 return internalObjectKeys$1(O, hiddenKeys$3);
527 var objectGetOwnPropertySymbols = {};
529 // eslint-disable-next-line es/no-object-getownpropertysymbols -- safe
530 objectGetOwnPropertySymbols.f = Object.getOwnPropertySymbols;
532 var getBuiltIn$8 = getBuiltIn$9;
533 var getOwnPropertyNamesModule$1 = objectGetOwnPropertyNames;
534 var getOwnPropertySymbolsModule$2 = objectGetOwnPropertySymbols;
535 var anObject$k = anObject$m;
537 // all object keys, includes non-enumerable and symbols
538 var ownKeys$1 = getBuiltIn$8('Reflect', 'ownKeys') || function ownKeys(it) {
539 var keys = getOwnPropertyNamesModule$1.f(anObject$k(it));
540 var getOwnPropertySymbols = getOwnPropertySymbolsModule$2.f;
541 return getOwnPropertySymbols ? keys.concat(getOwnPropertySymbols(it)) : keys;
545 var ownKeys = ownKeys$1;
546 var getOwnPropertyDescriptorModule$3 = objectGetOwnPropertyDescriptor;
547 var definePropertyModule$6 = objectDefineProperty;
549 var copyConstructorProperties$2 = function (target, source) {
550 var keys = ownKeys(source);
551 var defineProperty = definePropertyModule$6.f;
552 var getOwnPropertyDescriptor = getOwnPropertyDescriptorModule$3.f;
553 for (var i = 0; i < keys.length; i++) {
555 if (!has$e(target, key)) defineProperty(target, key, getOwnPropertyDescriptor(source, key));
559 var fails$J = fails$N;
561 var replacement = /#|\.prototype\./;
563 var isForced$5 = function (feature, detection) {
564 var value = data[normalize$1(feature)];
565 return value == POLYFILL ? true
566 : value == NATIVE ? false
567 : typeof detection == 'function' ? fails$J(detection)
571 var normalize$1 = isForced$5.normalize = function (string) {
572 return String(string).replace(replacement, '.').toLowerCase();
575 var data = isForced$5.data = {};
576 var NATIVE = isForced$5.NATIVE = 'N';
577 var POLYFILL = isForced$5.POLYFILL = 'P';
579 var isForced_1 = isForced$5;
581 var global$w = global$F;
582 var getOwnPropertyDescriptor$4 = objectGetOwnPropertyDescriptor.f;
583 var createNonEnumerableProperty$a = createNonEnumerableProperty$e;
584 var redefine$f = redefine$g.exports;
585 var setGlobal = setGlobal$3;
586 var copyConstructorProperties$1 = copyConstructorProperties$2;
587 var isForced$4 = isForced_1;
590 options.target - name of the target object
591 options.global - target is the global object
592 options.stat - export as static methods of target
593 options.proto - export as prototype methods of target
594 options.real - real prototype method for the `pure` version
595 options.forced - export even if the native feature is available
596 options.bind - bind methods to the target, required for the `pure` version
597 options.wrap - wrap constructors to preventing global pollution, required for the `pure` version
598 options.unsafe - use the simple assignment of property instead of delete + defineProperty
599 options.sham - add a flag to not completely full polyfills
600 options.enumerable - export as enumerable property
601 options.noTargetGet - prevent calling a getter on target
603 var _export = function (options, source) {
604 var TARGET = options.target;
605 var GLOBAL = options.global;
606 var STATIC = options.stat;
607 var FORCED, target, key, targetProperty, sourceProperty, descriptor;
611 target = global$w[TARGET] || setGlobal(TARGET, {});
613 target = (global$w[TARGET] || {}).prototype;
615 if (target) for (key in source) {
616 sourceProperty = source[key];
617 if (options.noTargetGet) {
618 descriptor = getOwnPropertyDescriptor$4(target, key);
619 targetProperty = descriptor && descriptor.value;
620 } else targetProperty = target[key];
621 FORCED = isForced$4(GLOBAL ? key : TARGET + (STATIC ? '.' : '#') + key, options.forced);
622 // contained in target
623 if (!FORCED && targetProperty !== undefined) {
624 if (typeof sourceProperty === typeof targetProperty) continue;
625 copyConstructorProperties$1(sourceProperty, targetProperty);
627 // add a flag to not completely full polyfills
628 if (options.sham || (targetProperty && targetProperty.sham)) {
629 createNonEnumerableProperty$a(sourceProperty, 'sham', true);
632 redefine$f(target, key, sourceProperty, options);
639 // https://tc39.es/ecma262/#sec-date.now
640 $$16({ target: 'Date', stat: true }, {
641 now: function now() {
642 return new Date().getTime();
646 var redefine$e = redefine$g.exports;
648 var DatePrototype$1 = Date.prototype;
649 var INVALID_DATE = 'Invalid Date';
650 var TO_STRING$1 = 'toString';
651 var nativeDateToString = DatePrototype$1[TO_STRING$1];
652 var getTime$1 = DatePrototype$1.getTime;
654 // `Date.prototype.toString` method
655 // https://tc39.es/ecma262/#sec-date.prototype.tostring
656 if (new Date(NaN) + '' != INVALID_DATE) {
657 redefine$e(DatePrototype$1, TO_STRING$1, function toString() {
658 var value = getTime$1.call(this);
659 // eslint-disable-next-line no-self-compare -- NaN check
660 return value === value ? nativeDateToString.call(this) : INVALID_DATE;
664 function _typeof(obj) {
665 "@babel/helpers - typeof";
667 if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
668 _typeof = function (obj) {
672 _typeof = function (obj) {
673 return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
680 function _classCallCheck$1(instance, Constructor) {
681 if (!(instance instanceof Constructor)) {
682 throw new TypeError("Cannot call a class as a function");
686 function _defineProperties$1(target, props) {
687 for (var i = 0; i < props.length; i++) {
688 var descriptor = props[i];
689 descriptor.enumerable = descriptor.enumerable || false;
690 descriptor.configurable = true;
691 if ("value" in descriptor) descriptor.writable = true;
692 Object.defineProperty(target, descriptor.key, descriptor);
696 function _createClass$1(Constructor, protoProps, staticProps) {
697 if (protoProps) _defineProperties$1(Constructor.prototype, protoProps);
698 if (staticProps) _defineProperties$1(Constructor, staticProps);
702 function _defineProperty(obj, key, value) {
704 Object.defineProperty(obj, key, {
717 function _slicedToArray(arr, i) {
718 return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest();
721 function _toConsumableArray(arr) {
722 return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
725 function _arrayWithoutHoles(arr) {
726 if (Array.isArray(arr)) return _arrayLikeToArray(arr);
729 function _arrayWithHoles(arr) {
730 if (Array.isArray(arr)) return arr;
733 function _iterableToArray(iter) {
734 if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
737 function _iterableToArrayLimit(arr, i) {
738 var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
740 if (_i == null) return;
748 for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
751 if (i && _arr.length === i) break;
758 if (!_n && _i["return"] != null) _i["return"]();
767 function _unsupportedIterableToArray(o, minLen) {
769 if (typeof o === "string") return _arrayLikeToArray(o, minLen);
770 var n = Object.prototype.toString.call(o).slice(8, -1);
771 if (n === "Object" && o.constructor) n = o.constructor.name;
772 if (n === "Map" || n === "Set") return Array.from(o);
773 if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
776 function _arrayLikeToArray(arr, len) {
777 if (len == null || len > arr.length) len = arr.length;
779 for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
784 function _nonIterableSpread() {
785 throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
788 function _nonIterableRest() {
789 throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
792 function _createForOfIteratorHelper(o, allowArrayLike) {
793 var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
796 if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
800 var F = function () {};
805 if (i >= o.length) return {
820 throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
823 var normalCompletion = true,
831 var step = it.next();
832 normalCompletion = step.done;
841 if (!normalCompletion && it.return != null) it.return();
843 if (didErr) throw err;
849 var wellKnownSymbolWrapped = {};
851 var getBuiltIn$7 = getBuiltIn$9;
853 var engineUserAgent = getBuiltIn$7('navigator', 'userAgent') || '';
855 var global$v = global$F;
856 var userAgent$5 = engineUserAgent;
858 var process$4 = global$v.process;
859 var versions = process$4 && process$4.versions;
860 var v8 = versions && versions.v8;
861 var match, version$1;
864 match = v8.split('.');
865 version$1 = match[0] < 4 ? 1 : match[0] + match[1];
866 } else if (userAgent$5) {
867 match = userAgent$5.match(/Edge\/(\d+)/);
868 if (!match || match[1] >= 74) {
869 match = userAgent$5.match(/Chrome\/(\d+)/);
870 if (match) version$1 = match[1];
874 var engineV8Version = version$1 && +version$1;
876 /* eslint-disable es/no-symbol -- required for testing */
878 var V8_VERSION$3 = engineV8Version;
879 var fails$I = fails$N;
881 // eslint-disable-next-line es/no-object-getownpropertysymbols -- required for testing
882 var nativeSymbol = !!Object.getOwnPropertySymbols && !fails$I(function () {
883 var symbol = Symbol();
884 // Chrome 38 Symbol has incorrect toString conversion
885 // `get-own-property-symbols` polyfill symbols converted to object are not Symbol instances
886 return !String(symbol) || !(Object(symbol) instanceof Symbol) ||
887 // Chrome 38-40 symbols are not inherited from DOM collections prototypes to instances
888 !Symbol.sham && V8_VERSION$3 && V8_VERSION$3 < 41;
891 /* eslint-disable es/no-symbol -- required for testing */
893 var NATIVE_SYMBOL$2 = nativeSymbol;
895 var useSymbolAsUid = NATIVE_SYMBOL$2
897 && typeof Symbol.iterator == 'symbol';
899 var global$u = global$F;
900 var shared$2 = shared$5.exports;
903 var NATIVE_SYMBOL$1 = nativeSymbol;
904 var USE_SYMBOL_AS_UID$1 = useSymbolAsUid;
906 var WellKnownSymbolsStore$1 = shared$2('wks');
907 var Symbol$1 = global$u.Symbol;
908 var createWellKnownSymbol = USE_SYMBOL_AS_UID$1 ? Symbol$1 : Symbol$1 && Symbol$1.withoutSetter || uid$3;
910 var wellKnownSymbol$s = function (name) {
911 if (!has$d(WellKnownSymbolsStore$1, name) || !(NATIVE_SYMBOL$1 || typeof WellKnownSymbolsStore$1[name] == 'string')) {
912 if (NATIVE_SYMBOL$1 && has$d(Symbol$1, name)) {
913 WellKnownSymbolsStore$1[name] = Symbol$1[name];
915 WellKnownSymbolsStore$1[name] = createWellKnownSymbol('Symbol.' + name);
917 } return WellKnownSymbolsStore$1[name];
920 var wellKnownSymbol$r = wellKnownSymbol$s;
922 wellKnownSymbolWrapped.f = wellKnownSymbol$r;
926 var wrappedWellKnownSymbolModule$1 = wellKnownSymbolWrapped;
927 var defineProperty$a = objectDefineProperty.f;
929 var defineWellKnownSymbol$4 = function (NAME) {
930 var Symbol = path.Symbol || (path.Symbol = {});
931 if (!has$c(Symbol, NAME)) defineProperty$a(Symbol, NAME, {
932 value: wrappedWellKnownSymbolModule$1.f(NAME)
936 var defineWellKnownSymbol$3 = defineWellKnownSymbol$4;
938 // `Symbol.iterator` well-known symbol
939 // https://tc39.es/ecma262/#sec-symbol.iterator
940 defineWellKnownSymbol$3('iterator');
942 var internalObjectKeys = objectKeysInternal;
943 var enumBugKeys$1 = enumBugKeys$3;
945 // `Object.keys` method
946 // https://tc39.es/ecma262/#sec-object.keys
947 // eslint-disable-next-line es/no-object-keys -- safe
948 var objectKeys$4 = Object.keys || function keys(O) {
949 return internalObjectKeys(O, enumBugKeys$1);
952 var DESCRIPTORS$i = descriptors;
953 var definePropertyModule$5 = objectDefineProperty;
954 var anObject$j = anObject$m;
955 var objectKeys$3 = objectKeys$4;
957 // `Object.defineProperties` method
958 // https://tc39.es/ecma262/#sec-object.defineproperties
959 // eslint-disable-next-line es/no-object-defineproperties -- safe
960 var objectDefineProperties = DESCRIPTORS$i ? Object.defineProperties : function defineProperties(O, Properties) {
962 var keys = objectKeys$3(Properties);
963 var length = keys.length;
966 while (length > index) definePropertyModule$5.f(O, key = keys[index++], Properties[key]);
970 var getBuiltIn$6 = getBuiltIn$9;
972 var html$2 = getBuiltIn$6('document', 'documentElement');
974 var anObject$i = anObject$m;
975 var defineProperties$2 = objectDefineProperties;
976 var enumBugKeys = enumBugKeys$3;
977 var hiddenKeys$2 = hiddenKeys$6;
979 var documentCreateElement = documentCreateElement$1;
980 var sharedKey$2 = sharedKey$4;
984 var PROTOTYPE$2 = 'prototype';
985 var SCRIPT = 'script';
986 var IE_PROTO$1 = sharedKey$2('IE_PROTO');
988 var EmptyConstructor = function () { /* empty */ };
990 var scriptTag = function (content) {
991 return LT + SCRIPT + GT + content + LT + '/' + SCRIPT + GT;
994 // Create object with fake `null` prototype: use ActiveX Object with cleared prototype
995 var NullProtoObjectViaActiveX = function (activeXDocument) {
996 activeXDocument.write(scriptTag(''));
997 activeXDocument.close();
998 var temp = activeXDocument.parentWindow.Object;
999 activeXDocument = null; // avoid memory leak
1003 // Create object with fake `null` prototype: use iframe Object with cleared prototype
1004 var NullProtoObjectViaIFrame = function () {
1005 // Thrash, waste and sodomy: IE GC bug
1006 var iframe = documentCreateElement('iframe');
1007 var JS = 'java' + SCRIPT + ':';
1009 iframe.style.display = 'none';
1010 html$1.appendChild(iframe);
1011 // https://github.com/zloirock/core-js/issues/475
1012 iframe.src = String(JS);
1013 iframeDocument = iframe.contentWindow.document;
1014 iframeDocument.open();
1015 iframeDocument.write(scriptTag('document.F=Object'));
1016 iframeDocument.close();
1017 return iframeDocument.F;
1020 // Check for document.domain and active x support
1021 // No need to use active x approach when document.domain is not set
1022 // see https://github.com/es-shims/es5-shim/issues/150
1023 // variation of https://github.com/kitcambridge/es5-shim/commit/4f738ac066346
1025 var activeXDocument;
1026 var NullProtoObject = function () {
1028 /* global ActiveXObject -- old IE */
1029 activeXDocument = document.domain && new ActiveXObject('htmlfile');
1030 } catch (error) { /* ignore */ }
1031 NullProtoObject = activeXDocument ? NullProtoObjectViaActiveX(activeXDocument) : NullProtoObjectViaIFrame();
1032 var length = enumBugKeys.length;
1033 while (length--) delete NullProtoObject[PROTOTYPE$2][enumBugKeys[length]];
1034 return NullProtoObject();
1037 hiddenKeys$2[IE_PROTO$1] = true;
1039 // `Object.create` method
1040 // https://tc39.es/ecma262/#sec-object.create
1041 var objectCreate = Object.create || function create(O, Properties) {
1044 EmptyConstructor[PROTOTYPE$2] = anObject$i(O);
1045 result = new EmptyConstructor();
1046 EmptyConstructor[PROTOTYPE$2] = null;
1047 // add "__proto__" for Object.getPrototypeOf polyfill
1048 result[IE_PROTO$1] = O;
1049 } else result = NullProtoObject();
1050 return Properties === undefined ? result : defineProperties$2(result, Properties);
1053 var wellKnownSymbol$q = wellKnownSymbol$s;
1054 var create$b = objectCreate;
1055 var definePropertyModule$4 = objectDefineProperty;
1057 var UNSCOPABLES = wellKnownSymbol$q('unscopables');
1058 var ArrayPrototype$1 = Array.prototype;
1060 // Array.prototype[@@unscopables]
1061 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1062 if (ArrayPrototype$1[UNSCOPABLES] == undefined) {
1063 definePropertyModule$4.f(ArrayPrototype$1, UNSCOPABLES, {
1065 value: create$b(null)
1069 // add a key to Array.prototype[@@unscopables]
1070 var addToUnscopables$5 = function (key) {
1071 ArrayPrototype$1[UNSCOPABLES][key] = true;
1076 var fails$H = fails$N;
1078 var correctPrototypeGetter = !fails$H(function () {
1079 function F() { /* empty */ }
1080 F.prototype.constructor = null;
1081 // eslint-disable-next-line es/no-object-getprototypeof -- required for testing
1082 return Object.getPrototypeOf(new F()) !== F.prototype;
1086 var toObject$g = toObject$i;
1087 var sharedKey$1 = sharedKey$4;
1088 var CORRECT_PROTOTYPE_GETTER$1 = correctPrototypeGetter;
1090 var IE_PROTO = sharedKey$1('IE_PROTO');
1091 var ObjectPrototype$3 = Object.prototype;
1093 // `Object.getPrototypeOf` method
1094 // https://tc39.es/ecma262/#sec-object.getprototypeof
1095 // eslint-disable-next-line es/no-object-getprototypeof -- safe
1096 var objectGetPrototypeOf = CORRECT_PROTOTYPE_GETTER$1 ? Object.getPrototypeOf : function (O) {
1098 if (has$b(O, IE_PROTO)) return O[IE_PROTO];
1099 if (typeof O.constructor == 'function' && O instanceof O.constructor) {
1100 return O.constructor.prototype;
1101 } return O instanceof Object ? ObjectPrototype$3 : null;
1104 var fails$G = fails$N;
1105 var getPrototypeOf$4 = objectGetPrototypeOf;
1106 var createNonEnumerableProperty$9 = createNonEnumerableProperty$e;
1108 var wellKnownSymbol$p = wellKnownSymbol$s;
1110 var ITERATOR$8 = wellKnownSymbol$p('iterator');
1111 var BUGGY_SAFARI_ITERATORS$1 = false;
1113 var returnThis$2 = function () { return this; };
1115 // `%IteratorPrototype%` object
1116 // https://tc39.es/ecma262/#sec-%iteratorprototype%-object
1117 var IteratorPrototype$2, PrototypeOfArrayIteratorPrototype, arrayIterator;
1119 /* eslint-disable es/no-array-prototype-keys -- safe */
1121 arrayIterator = [].keys();
1122 // Safari 8 has buggy iterators w/o `next`
1123 if (!('next' in arrayIterator)) BUGGY_SAFARI_ITERATORS$1 = true;
1125 PrototypeOfArrayIteratorPrototype = getPrototypeOf$4(getPrototypeOf$4(arrayIterator));
1126 if (PrototypeOfArrayIteratorPrototype !== Object.prototype) IteratorPrototype$2 = PrototypeOfArrayIteratorPrototype;
1130 var NEW_ITERATOR_PROTOTYPE = IteratorPrototype$2 == undefined || fails$G(function () {
1132 // FF44- legacy iterators case
1133 return IteratorPrototype$2[ITERATOR$8].call(test) !== test;
1136 if (NEW_ITERATOR_PROTOTYPE) IteratorPrototype$2 = {};
1138 // `%IteratorPrototype%[@@iterator]()` method
1139 // https://tc39.es/ecma262/#sec-%iteratorprototype%-@@iterator
1140 if (!has$a(IteratorPrototype$2, ITERATOR$8)) {
1141 createNonEnumerableProperty$9(IteratorPrototype$2, ITERATOR$8, returnThis$2);
1144 var iteratorsCore = {
1145 IteratorPrototype: IteratorPrototype$2,
1146 BUGGY_SAFARI_ITERATORS: BUGGY_SAFARI_ITERATORS$1
1149 var defineProperty$9 = objectDefineProperty.f;
1151 var wellKnownSymbol$o = wellKnownSymbol$s;
1153 var TO_STRING_TAG$4 = wellKnownSymbol$o('toStringTag');
1155 var setToStringTag$a = function (it, TAG, STATIC) {
1156 if (it && !has$9(it = STATIC ? it : it.prototype, TO_STRING_TAG$4)) {
1157 defineProperty$9(it, TO_STRING_TAG$4, { configurable: true, value: TAG });
1161 var IteratorPrototype$1 = iteratorsCore.IteratorPrototype;
1162 var create$a = objectCreate;
1163 var createPropertyDescriptor$4 = createPropertyDescriptor$7;
1164 var setToStringTag$9 = setToStringTag$a;
1165 var Iterators$4 = iterators;
1167 var returnThis$1 = function () { return this; };
1169 var createIteratorConstructor$2 = function (IteratorConstructor, NAME, next) {
1170 var TO_STRING_TAG = NAME + ' Iterator';
1171 IteratorConstructor.prototype = create$a(IteratorPrototype$1, { next: createPropertyDescriptor$4(1, next) });
1172 setToStringTag$9(IteratorConstructor, TO_STRING_TAG, false);
1173 Iterators$4[TO_STRING_TAG] = returnThis$1;
1174 return IteratorConstructor;
1177 var isObject$m = isObject$r;
1179 var aPossiblePrototype$1 = function (it) {
1180 if (!isObject$m(it) && it !== null) {
1181 throw TypeError("Can't set " + String(it) + ' as a prototype');
1185 /* eslint-disable no-proto -- safe */
1187 var anObject$h = anObject$m;
1188 var aPossiblePrototype = aPossiblePrototype$1;
1190 // `Object.setPrototypeOf` method
1191 // https://tc39.es/ecma262/#sec-object.setprototypeof
1192 // Works with __proto__ only. Old v8 can't work with null proto objects.
1193 // eslint-disable-next-line es/no-object-setprototypeof -- safe
1194 var objectSetPrototypeOf = Object.setPrototypeOf || ('__proto__' in {} ? function () {
1195 var CORRECT_SETTER = false;
1199 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
1200 setter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set;
1201 setter.call(test, []);
1202 CORRECT_SETTER = test instanceof Array;
1203 } catch (error) { /* empty */ }
1204 return function setPrototypeOf(O, proto) {
1206 aPossiblePrototype(proto);
1207 if (CORRECT_SETTER) setter.call(O, proto);
1208 else O.__proto__ = proto;
1214 var createIteratorConstructor$1 = createIteratorConstructor$2;
1215 var getPrototypeOf$3 = objectGetPrototypeOf;
1216 var setPrototypeOf$6 = objectSetPrototypeOf;
1217 var setToStringTag$8 = setToStringTag$a;
1218 var createNonEnumerableProperty$8 = createNonEnumerableProperty$e;
1219 var redefine$d = redefine$g.exports;
1220 var wellKnownSymbol$n = wellKnownSymbol$s;
1221 var Iterators$3 = iterators;
1222 var IteratorsCore = iteratorsCore;
1224 var IteratorPrototype = IteratorsCore.IteratorPrototype;
1225 var BUGGY_SAFARI_ITERATORS = IteratorsCore.BUGGY_SAFARI_ITERATORS;
1226 var ITERATOR$7 = wellKnownSymbol$n('iterator');
1228 var VALUES = 'values';
1229 var ENTRIES = 'entries';
1231 var returnThis = function () { return this; };
1233 var defineIterator$3 = function (Iterable, NAME, IteratorConstructor, next, DEFAULT, IS_SET, FORCED) {
1234 createIteratorConstructor$1(IteratorConstructor, NAME, next);
1236 var getIterationMethod = function (KIND) {
1237 if (KIND === DEFAULT && defaultIterator) return defaultIterator;
1238 if (!BUGGY_SAFARI_ITERATORS && KIND in IterablePrototype) return IterablePrototype[KIND];
1240 case KEYS: return function keys() { return new IteratorConstructor(this, KIND); };
1241 case VALUES: return function values() { return new IteratorConstructor(this, KIND); };
1242 case ENTRIES: return function entries() { return new IteratorConstructor(this, KIND); };
1243 } return function () { return new IteratorConstructor(this); };
1246 var TO_STRING_TAG = NAME + ' Iterator';
1247 var INCORRECT_VALUES_NAME = false;
1248 var IterablePrototype = Iterable.prototype;
1249 var nativeIterator = IterablePrototype[ITERATOR$7]
1250 || IterablePrototype['@@iterator']
1251 || DEFAULT && IterablePrototype[DEFAULT];
1252 var defaultIterator = !BUGGY_SAFARI_ITERATORS && nativeIterator || getIterationMethod(DEFAULT);
1253 var anyNativeIterator = NAME == 'Array' ? IterablePrototype.entries || nativeIterator : nativeIterator;
1254 var CurrentIteratorPrototype, methods, KEY;
1257 if (anyNativeIterator) {
1258 CurrentIteratorPrototype = getPrototypeOf$3(anyNativeIterator.call(new Iterable()));
1259 if (IteratorPrototype !== Object.prototype && CurrentIteratorPrototype.next) {
1260 if (getPrototypeOf$3(CurrentIteratorPrototype) !== IteratorPrototype) {
1261 if (setPrototypeOf$6) {
1262 setPrototypeOf$6(CurrentIteratorPrototype, IteratorPrototype);
1263 } else if (typeof CurrentIteratorPrototype[ITERATOR$7] != 'function') {
1264 createNonEnumerableProperty$8(CurrentIteratorPrototype, ITERATOR$7, returnThis);
1267 // Set @@toStringTag to native iterators
1268 setToStringTag$8(CurrentIteratorPrototype, TO_STRING_TAG, true);
1272 // fix Array.prototype.{ values, @@iterator }.name in V8 / FF
1273 if (DEFAULT == VALUES && nativeIterator && nativeIterator.name !== VALUES) {
1274 INCORRECT_VALUES_NAME = true;
1275 defaultIterator = function values() { return nativeIterator.call(this); };
1279 if (IterablePrototype[ITERATOR$7] !== defaultIterator) {
1280 createNonEnumerableProperty$8(IterablePrototype, ITERATOR$7, defaultIterator);
1282 Iterators$3[NAME] = defaultIterator;
1284 // export additional methods
1287 values: getIterationMethod(VALUES),
1288 keys: IS_SET ? defaultIterator : getIterationMethod(KEYS),
1289 entries: getIterationMethod(ENTRIES)
1291 if (FORCED) for (KEY in methods) {
1292 if (BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME || !(KEY in IterablePrototype)) {
1293 redefine$d(IterablePrototype, KEY, methods[KEY]);
1295 } else $$15({ target: NAME, proto: true, forced: BUGGY_SAFARI_ITERATORS || INCORRECT_VALUES_NAME }, methods);
1301 var toIndexedObject$7 = toIndexedObject$b;
1302 var addToUnscopables$4 = addToUnscopables$5;
1303 var Iterators$2 = iterators;
1304 var InternalStateModule$8 = internalState;
1305 var defineIterator$2 = defineIterator$3;
1307 var ARRAY_ITERATOR = 'Array Iterator';
1308 var setInternalState$8 = InternalStateModule$8.set;
1309 var getInternalState$6 = InternalStateModule$8.getterFor(ARRAY_ITERATOR);
1311 // `Array.prototype.entries` method
1312 // https://tc39.es/ecma262/#sec-array.prototype.entries
1313 // `Array.prototype.keys` method
1314 // https://tc39.es/ecma262/#sec-array.prototype.keys
1315 // `Array.prototype.values` method
1316 // https://tc39.es/ecma262/#sec-array.prototype.values
1317 // `Array.prototype[@@iterator]` method
1318 // https://tc39.es/ecma262/#sec-array.prototype-@@iterator
1319 // `CreateArrayIterator` internal method
1320 // https://tc39.es/ecma262/#sec-createarrayiterator
1321 var es_array_iterator = defineIterator$2(Array, 'Array', function (iterated, kind) {
1322 setInternalState$8(this, {
1323 type: ARRAY_ITERATOR,
1324 target: toIndexedObject$7(iterated), // target
1325 index: 0, // next index
1328 // `%ArrayIteratorPrototype%.next` method
1329 // https://tc39.es/ecma262/#sec-%arrayiteratorprototype%.next
1331 var state = getInternalState$6(this);
1332 var target = state.target;
1333 var kind = state.kind;
1334 var index = state.index++;
1335 if (!target || index >= target.length) {
1336 state.target = undefined;
1337 return { value: undefined, done: true };
1339 if (kind == 'keys') return { value: index, done: false };
1340 if (kind == 'values') return { value: target[index], done: false };
1341 return { value: [index, target[index]], done: false };
1344 // argumentsList[@@iterator] is %ArrayProto_values%
1345 // https://tc39.es/ecma262/#sec-createunmappedargumentsobject
1346 // https://tc39.es/ecma262/#sec-createmappedargumentsobject
1347 Iterators$2.Arguments = Iterators$2.Array;
1349 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
1350 addToUnscopables$4('keys');
1351 addToUnscopables$4('values');
1352 addToUnscopables$4('entries');
1354 var wellKnownSymbol$m = wellKnownSymbol$s;
1356 var TO_STRING_TAG$3 = wellKnownSymbol$m('toStringTag');
1359 test$2[TO_STRING_TAG$3] = 'z';
1361 var toStringTagSupport = String(test$2) === '[object z]';
1363 var TO_STRING_TAG_SUPPORT$2 = toStringTagSupport;
1364 var classofRaw = classofRaw$1;
1365 var wellKnownSymbol$l = wellKnownSymbol$s;
1367 var TO_STRING_TAG$2 = wellKnownSymbol$l('toStringTag');
1369 var CORRECT_ARGUMENTS = classofRaw(function () { return arguments; }()) == 'Arguments';
1371 // fallback for IE11 Script Access Denied error
1372 var tryGet = function (it, key) {
1375 } catch (error) { /* empty */ }
1378 // getting tag from ES6+ `Object.prototype.toString`
1379 var classof$b = TO_STRING_TAG_SUPPORT$2 ? classofRaw : function (it) {
1381 return it === undefined ? 'Undefined' : it === null ? 'Null'
1382 // @@toStringTag case
1383 : typeof (tag = tryGet(O = Object(it), TO_STRING_TAG$2)) == 'string' ? tag
1385 : CORRECT_ARGUMENTS ? classofRaw(O)
1386 // ES3 arguments fallback
1387 : (result = classofRaw(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : result;
1390 var TO_STRING_TAG_SUPPORT$1 = toStringTagSupport;
1391 var classof$a = classof$b;
1393 // `Object.prototype.toString` method implementation
1394 // https://tc39.es/ecma262/#sec-object.prototype.tostring
1395 var objectToString$1 = TO_STRING_TAG_SUPPORT$1 ? {}.toString : function toString() {
1396 return '[object ' + classof$a(this) + ']';
1399 var TO_STRING_TAG_SUPPORT = toStringTagSupport;
1400 var redefine$c = redefine$g.exports;
1401 var toString$1 = objectToString$1;
1403 // `Object.prototype.toString` method
1404 // https://tc39.es/ecma262/#sec-object.prototype.tostring
1405 if (!TO_STRING_TAG_SUPPORT) {
1406 redefine$c(Object.prototype, 'toString', toString$1, { unsafe: true });
1409 var toInteger$8 = toInteger$b;
1410 var requireObjectCoercible$b = requireObjectCoercible$e;
1412 // `String.prototype.{ codePointAt, at }` methods implementation
1413 var createMethod$5 = function (CONVERT_TO_STRING) {
1414 return function ($this, pos) {
1415 var S = String(requireObjectCoercible$b($this));
1416 var position = toInteger$8(pos);
1417 var size = S.length;
1419 if (position < 0 || position >= size) return CONVERT_TO_STRING ? '' : undefined;
1420 first = S.charCodeAt(position);
1421 return first < 0xD800 || first > 0xDBFF || position + 1 === size
1422 || (second = S.charCodeAt(position + 1)) < 0xDC00 || second > 0xDFFF
1423 ? CONVERT_TO_STRING ? S.charAt(position) : first
1424 : CONVERT_TO_STRING ? S.slice(position, position + 2) : (first - 0xD800 << 10) + (second - 0xDC00) + 0x10000;
1428 var stringMultibyte = {
1429 // `String.prototype.codePointAt` method
1430 // https://tc39.es/ecma262/#sec-string.prototype.codepointat
1431 codeAt: createMethod$5(false),
1432 // `String.prototype.at` method
1433 // https://github.com/mathiasbynens/String.prototype.at
1434 charAt: createMethod$5(true)
1437 var charAt$1 = stringMultibyte.charAt;
1438 var InternalStateModule$7 = internalState;
1439 var defineIterator$1 = defineIterator$3;
1441 var STRING_ITERATOR = 'String Iterator';
1442 var setInternalState$7 = InternalStateModule$7.set;
1443 var getInternalState$5 = InternalStateModule$7.getterFor(STRING_ITERATOR);
1445 // `String.prototype[@@iterator]` method
1446 // https://tc39.es/ecma262/#sec-string.prototype-@@iterator
1447 defineIterator$1(String, 'String', function (iterated) {
1448 setInternalState$7(this, {
1449 type: STRING_ITERATOR,
1450 string: String(iterated),
1453 // `%StringIteratorPrototype%.next` method
1454 // https://tc39.es/ecma262/#sec-%stringiteratorprototype%.next
1455 }, function next() {
1456 var state = getInternalState$5(this);
1457 var string = state.string;
1458 var index = state.index;
1460 if (index >= string.length) return { value: undefined, done: true };
1461 point = charAt$1(string, index);
1462 state.index += point.length;
1463 return { value: point, done: false };
1466 // iterable DOM collections
1467 // flag - `iterable` interface - 'entries', 'keys', 'values', 'forEach' methods
1468 var domIterables = {
1470 CSSStyleDeclaration: 0,
1476 DataTransferItemList: 0,
1478 HTMLAllCollection: 0,
1481 HTMLSelectElement: 0,
1486 PaintRequestList: 0,
1494 SVGTransformList: 0,
1495 SourceBufferList: 0,
1497 TextTrackCueList: 0,
1502 var global$t = global$F;
1503 var DOMIterables$1 = domIterables;
1504 var ArrayIteratorMethods = es_array_iterator;
1505 var createNonEnumerableProperty$7 = createNonEnumerableProperty$e;
1506 var wellKnownSymbol$k = wellKnownSymbol$s;
1508 var ITERATOR$6 = wellKnownSymbol$k('iterator');
1509 var TO_STRING_TAG$1 = wellKnownSymbol$k('toStringTag');
1510 var ArrayValues = ArrayIteratorMethods.values;
1512 for (var COLLECTION_NAME$1 in DOMIterables$1) {
1513 var Collection$1 = global$t[COLLECTION_NAME$1];
1514 var CollectionPrototype$1 = Collection$1 && Collection$1.prototype;
1515 if (CollectionPrototype$1) {
1516 // some Chrome versions have non-configurable methods on DOMTokenList
1517 if (CollectionPrototype$1[ITERATOR$6] !== ArrayValues) try {
1518 createNonEnumerableProperty$7(CollectionPrototype$1, ITERATOR$6, ArrayValues);
1520 CollectionPrototype$1[ITERATOR$6] = ArrayValues;
1522 if (!CollectionPrototype$1[TO_STRING_TAG$1]) {
1523 createNonEnumerableProperty$7(CollectionPrototype$1, TO_STRING_TAG$1, COLLECTION_NAME$1);
1525 if (DOMIterables$1[COLLECTION_NAME$1]) for (var METHOD_NAME in ArrayIteratorMethods) {
1526 // some Chrome versions have non-configurable methods on DOMTokenList
1527 if (CollectionPrototype$1[METHOD_NAME] !== ArrayIteratorMethods[METHOD_NAME]) try {
1528 createNonEnumerableProperty$7(CollectionPrototype$1, METHOD_NAME, ArrayIteratorMethods[METHOD_NAME]);
1530 CollectionPrototype$1[METHOD_NAME] = ArrayIteratorMethods[METHOD_NAME];
1536 var classof$9 = classofRaw$1;
1538 // `IsArray` abstract operation
1539 // https://tc39.es/ecma262/#sec-isarray
1540 // eslint-disable-next-line es/no-array-isarray -- safe
1541 var isArray$6 = Array.isArray || function isArray(arg) {
1542 return classof$9(arg) == 'Array';
1545 var objectGetOwnPropertyNamesExternal = {};
1547 /* eslint-disable es/no-object-getownpropertynames -- safe */
1549 var toIndexedObject$6 = toIndexedObject$b;
1550 var $getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
1552 var toString = {}.toString;
1554 var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames
1555 ? Object.getOwnPropertyNames(window) : [];
1557 var getWindowNames = function (it) {
1559 return $getOwnPropertyNames$1(it);
1561 return windowNames.slice();
1565 // fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
1566 objectGetOwnPropertyNamesExternal.f = function getOwnPropertyNames(it) {
1567 return windowNames && toString.call(it) == '[object Window]'
1568 ? getWindowNames(it)
1569 : $getOwnPropertyNames$1(toIndexedObject$6(it));
1572 var aFunction$9 = function (it) {
1573 if (typeof it != 'function') {
1574 throw TypeError(String(it) + ' is not a function');
1578 var aFunction$8 = aFunction$9;
1580 // optional / simple context binding
1581 var functionBindContext = function (fn, that, length) {
1583 if (that === undefined) return fn;
1585 case 0: return function () {
1586 return fn.call(that);
1588 case 1: return function (a) {
1589 return fn.call(that, a);
1591 case 2: return function (a, b) {
1592 return fn.call(that, a, b);
1594 case 3: return function (a, b, c) {
1595 return fn.call(that, a, b, c);
1598 return function (/* ...args */) {
1599 return fn.apply(that, arguments);
1603 var isObject$l = isObject$r;
1604 var isArray$5 = isArray$6;
1605 var wellKnownSymbol$j = wellKnownSymbol$s;
1607 var SPECIES$6 = wellKnownSymbol$j('species');
1609 // `ArraySpeciesCreate` abstract operation
1610 // https://tc39.es/ecma262/#sec-arrayspeciescreate
1611 var arraySpeciesCreate$3 = function (originalArray, length) {
1613 if (isArray$5(originalArray)) {
1614 C = originalArray.constructor;
1615 // cross-realm fallback
1616 if (typeof C == 'function' && (C === Array || isArray$5(C.prototype))) C = undefined;
1617 else if (isObject$l(C)) {
1619 if (C === null) C = undefined;
1621 } return new (C === undefined ? Array : C)(length === 0 ? 0 : length);
1624 var bind$b = functionBindContext;
1625 var IndexedObject$3 = indexedObject;
1626 var toObject$f = toObject$i;
1627 var toLength$o = toLength$q;
1628 var arraySpeciesCreate$2 = arraySpeciesCreate$3;
1632 // `Array.prototype.{ forEach, map, filter, some, every, find, findIndex, filterOut }` methods implementation
1633 var createMethod$4 = function (TYPE) {
1634 var IS_MAP = TYPE == 1;
1635 var IS_FILTER = TYPE == 2;
1636 var IS_SOME = TYPE == 3;
1637 var IS_EVERY = TYPE == 4;
1638 var IS_FIND_INDEX = TYPE == 6;
1639 var IS_FILTER_OUT = TYPE == 7;
1640 var NO_HOLES = TYPE == 5 || IS_FIND_INDEX;
1641 return function ($this, callbackfn, that, specificCreate) {
1642 var O = toObject$f($this);
1643 var self = IndexedObject$3(O);
1644 var boundFunction = bind$b(callbackfn, that, 3);
1645 var length = toLength$o(self.length);
1647 var create = specificCreate || arraySpeciesCreate$2;
1648 var target = IS_MAP ? create($this, length) : IS_FILTER || IS_FILTER_OUT ? create($this, 0) : undefined;
1650 for (;length > index; index++) if (NO_HOLES || index in self) {
1651 value = self[index];
1652 result = boundFunction(value, index, O);
1654 if (IS_MAP) target[index] = result; // map
1655 else if (result) switch (TYPE) {
1656 case 3: return true; // some
1657 case 5: return value; // find
1658 case 6: return index; // findIndex
1659 case 2: push.call(target, value); // filter
1660 } else switch (TYPE) {
1661 case 4: return false; // every
1662 case 7: push.call(target, value); // filterOut
1666 return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : target;
1670 var arrayIteration = {
1671 // `Array.prototype.forEach` method
1672 // https://tc39.es/ecma262/#sec-array.prototype.foreach
1673 forEach: createMethod$4(0),
1674 // `Array.prototype.map` method
1675 // https://tc39.es/ecma262/#sec-array.prototype.map
1676 map: createMethod$4(1),
1677 // `Array.prototype.filter` method
1678 // https://tc39.es/ecma262/#sec-array.prototype.filter
1679 filter: createMethod$4(2),
1680 // `Array.prototype.some` method
1681 // https://tc39.es/ecma262/#sec-array.prototype.some
1682 some: createMethod$4(3),
1683 // `Array.prototype.every` method
1684 // https://tc39.es/ecma262/#sec-array.prototype.every
1685 every: createMethod$4(4),
1686 // `Array.prototype.find` method
1687 // https://tc39.es/ecma262/#sec-array.prototype.find
1688 find: createMethod$4(5),
1689 // `Array.prototype.findIndex` method
1690 // https://tc39.es/ecma262/#sec-array.prototype.findIndex
1691 findIndex: createMethod$4(6),
1692 // `Array.prototype.filterOut` method
1693 // https://github.com/tc39/proposal-array-filtering
1694 filterOut: createMethod$4(7)
1698 var global$s = global$F;
1699 var getBuiltIn$5 = getBuiltIn$9;
1700 var DESCRIPTORS$h = descriptors;
1701 var NATIVE_SYMBOL = nativeSymbol;
1702 var USE_SYMBOL_AS_UID = useSymbolAsUid;
1703 var fails$F = fails$N;
1705 var isArray$4 = isArray$6;
1706 var isObject$k = isObject$r;
1707 var anObject$g = anObject$m;
1708 var toObject$e = toObject$i;
1709 var toIndexedObject$5 = toIndexedObject$b;
1710 var toPrimitive$4 = toPrimitive$7;
1711 var createPropertyDescriptor$3 = createPropertyDescriptor$7;
1712 var nativeObjectCreate = objectCreate;
1713 var objectKeys$2 = objectKeys$4;
1714 var getOwnPropertyNamesModule = objectGetOwnPropertyNames;
1715 var getOwnPropertyNamesExternal = objectGetOwnPropertyNamesExternal;
1716 var getOwnPropertySymbolsModule$1 = objectGetOwnPropertySymbols;
1717 var getOwnPropertyDescriptorModule$2 = objectGetOwnPropertyDescriptor;
1718 var definePropertyModule$3 = objectDefineProperty;
1719 var propertyIsEnumerableModule$1 = objectPropertyIsEnumerable;
1720 var createNonEnumerableProperty$6 = createNonEnumerableProperty$e;
1721 var redefine$b = redefine$g.exports;
1722 var shared$1 = shared$5.exports;
1723 var sharedKey = sharedKey$4;
1724 var hiddenKeys$1 = hiddenKeys$6;
1726 var wellKnownSymbol$i = wellKnownSymbol$s;
1727 var wrappedWellKnownSymbolModule = wellKnownSymbolWrapped;
1728 var defineWellKnownSymbol$2 = defineWellKnownSymbol$4;
1729 var setToStringTag$7 = setToStringTag$a;
1730 var InternalStateModule$6 = internalState;
1731 var $forEach$2 = arrayIteration.forEach;
1733 var HIDDEN = sharedKey('hidden');
1734 var SYMBOL = 'Symbol';
1735 var PROTOTYPE$1 = 'prototype';
1736 var TO_PRIMITIVE = wellKnownSymbol$i('toPrimitive');
1737 var setInternalState$6 = InternalStateModule$6.set;
1738 var getInternalState$4 = InternalStateModule$6.getterFor(SYMBOL);
1739 var ObjectPrototype$2 = Object[PROTOTYPE$1];
1740 var $Symbol = global$s.Symbol;
1741 var $stringify = getBuiltIn$5('JSON', 'stringify');
1742 var nativeGetOwnPropertyDescriptor$2 = getOwnPropertyDescriptorModule$2.f;
1743 var nativeDefineProperty$1 = definePropertyModule$3.f;
1744 var nativeGetOwnPropertyNames = getOwnPropertyNamesExternal.f;
1745 var nativePropertyIsEnumerable = propertyIsEnumerableModule$1.f;
1746 var AllSymbols = shared$1('symbols');
1747 var ObjectPrototypeSymbols = shared$1('op-symbols');
1748 var StringToSymbolRegistry = shared$1('string-to-symbol-registry');
1749 var SymbolToStringRegistry = shared$1('symbol-to-string-registry');
1750 var WellKnownSymbolsStore = shared$1('wks');
1751 var QObject = global$s.QObject;
1752 // Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173
1753 var USE_SETTER = !QObject || !QObject[PROTOTYPE$1] || !QObject[PROTOTYPE$1].findChild;
1755 // fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
1756 var setSymbolDescriptor = DESCRIPTORS$h && fails$F(function () {
1757 return nativeObjectCreate(nativeDefineProperty$1({}, 'a', {
1758 get: function () { return nativeDefineProperty$1(this, 'a', { value: 7 }).a; }
1760 }) ? function (O, P, Attributes) {
1761 var ObjectPrototypeDescriptor = nativeGetOwnPropertyDescriptor$2(ObjectPrototype$2, P);
1762 if (ObjectPrototypeDescriptor) delete ObjectPrototype$2[P];
1763 nativeDefineProperty$1(O, P, Attributes);
1764 if (ObjectPrototypeDescriptor && O !== ObjectPrototype$2) {
1765 nativeDefineProperty$1(ObjectPrototype$2, P, ObjectPrototypeDescriptor);
1767 } : nativeDefineProperty$1;
1769 var wrap$2 = function (tag, description) {
1770 var symbol = AllSymbols[tag] = nativeObjectCreate($Symbol[PROTOTYPE$1]);
1771 setInternalState$6(symbol, {
1774 description: description
1776 if (!DESCRIPTORS$h) symbol.description = description;
1780 var isSymbol$1 = USE_SYMBOL_AS_UID ? function (it) {
1781 return typeof it == 'symbol';
1783 return Object(it) instanceof $Symbol;
1786 var $defineProperty = function defineProperty(O, P, Attributes) {
1787 if (O === ObjectPrototype$2) $defineProperty(ObjectPrototypeSymbols, P, Attributes);
1789 var key = toPrimitive$4(P, true);
1790 anObject$g(Attributes);
1791 if (has$8(AllSymbols, key)) {
1792 if (!Attributes.enumerable) {
1793 if (!has$8(O, HIDDEN)) nativeDefineProperty$1(O, HIDDEN, createPropertyDescriptor$3(1, {}));
1794 O[HIDDEN][key] = true;
1796 if (has$8(O, HIDDEN) && O[HIDDEN][key]) O[HIDDEN][key] = false;
1797 Attributes = nativeObjectCreate(Attributes, { enumerable: createPropertyDescriptor$3(0, false) });
1798 } return setSymbolDescriptor(O, key, Attributes);
1799 } return nativeDefineProperty$1(O, key, Attributes);
1802 var $defineProperties = function defineProperties(O, Properties) {
1804 var properties = toIndexedObject$5(Properties);
1805 var keys = objectKeys$2(properties).concat($getOwnPropertySymbols(properties));
1806 $forEach$2(keys, function (key) {
1807 if (!DESCRIPTORS$h || $propertyIsEnumerable.call(properties, key)) $defineProperty(O, key, properties[key]);
1812 var $create = function create(O, Properties) {
1813 return Properties === undefined ? nativeObjectCreate(O) : $defineProperties(nativeObjectCreate(O), Properties);
1816 var $propertyIsEnumerable = function propertyIsEnumerable(V) {
1817 var P = toPrimitive$4(V, true);
1818 var enumerable = nativePropertyIsEnumerable.call(this, P);
1819 if (this === ObjectPrototype$2 && has$8(AllSymbols, P) && !has$8(ObjectPrototypeSymbols, P)) return false;
1820 return enumerable || !has$8(this, P) || !has$8(AllSymbols, P) || has$8(this, HIDDEN) && this[HIDDEN][P] ? enumerable : true;
1823 var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(O, P) {
1824 var it = toIndexedObject$5(O);
1825 var key = toPrimitive$4(P, true);
1826 if (it === ObjectPrototype$2 && has$8(AllSymbols, key) && !has$8(ObjectPrototypeSymbols, key)) return;
1827 var descriptor = nativeGetOwnPropertyDescriptor$2(it, key);
1828 if (descriptor && has$8(AllSymbols, key) && !(has$8(it, HIDDEN) && it[HIDDEN][key])) {
1829 descriptor.enumerable = true;
1834 var $getOwnPropertyNames = function getOwnPropertyNames(O) {
1835 var names = nativeGetOwnPropertyNames(toIndexedObject$5(O));
1837 $forEach$2(names, function (key) {
1838 if (!has$8(AllSymbols, key) && !has$8(hiddenKeys$1, key)) result.push(key);
1843 var $getOwnPropertySymbols = function getOwnPropertySymbols(O) {
1844 var IS_OBJECT_PROTOTYPE = O === ObjectPrototype$2;
1845 var names = nativeGetOwnPropertyNames(IS_OBJECT_PROTOTYPE ? ObjectPrototypeSymbols : toIndexedObject$5(O));
1847 $forEach$2(names, function (key) {
1848 if (has$8(AllSymbols, key) && (!IS_OBJECT_PROTOTYPE || has$8(ObjectPrototype$2, key))) {
1849 result.push(AllSymbols[key]);
1855 // `Symbol` constructor
1856 // https://tc39.es/ecma262/#sec-symbol-constructor
1857 if (!NATIVE_SYMBOL) {
1858 $Symbol = function Symbol() {
1859 if (this instanceof $Symbol) throw TypeError('Symbol is not a constructor');
1860 var description = !arguments.length || arguments[0] === undefined ? undefined : String(arguments[0]);
1861 var tag = uid$2(description);
1862 var setter = function (value) {
1863 if (this === ObjectPrototype$2) setter.call(ObjectPrototypeSymbols, value);
1864 if (has$8(this, HIDDEN) && has$8(this[HIDDEN], tag)) this[HIDDEN][tag] = false;
1865 setSymbolDescriptor(this, tag, createPropertyDescriptor$3(1, value));
1867 if (DESCRIPTORS$h && USE_SETTER) setSymbolDescriptor(ObjectPrototype$2, tag, { configurable: true, set: setter });
1868 return wrap$2(tag, description);
1871 redefine$b($Symbol[PROTOTYPE$1], 'toString', function toString() {
1872 return getInternalState$4(this).tag;
1875 redefine$b($Symbol, 'withoutSetter', function (description) {
1876 return wrap$2(uid$2(description), description);
1879 propertyIsEnumerableModule$1.f = $propertyIsEnumerable;
1880 definePropertyModule$3.f = $defineProperty;
1881 getOwnPropertyDescriptorModule$2.f = $getOwnPropertyDescriptor;
1882 getOwnPropertyNamesModule.f = getOwnPropertyNamesExternal.f = $getOwnPropertyNames;
1883 getOwnPropertySymbolsModule$1.f = $getOwnPropertySymbols;
1885 wrappedWellKnownSymbolModule.f = function (name) {
1886 return wrap$2(wellKnownSymbol$i(name), name);
1889 if (DESCRIPTORS$h) {
1890 // https://github.com/tc39/proposal-Symbol-description
1891 nativeDefineProperty$1($Symbol[PROTOTYPE$1], 'description', {
1893 get: function description() {
1894 return getInternalState$4(this).description;
1898 redefine$b(ObjectPrototype$2, 'propertyIsEnumerable', $propertyIsEnumerable, { unsafe: true });
1903 $$14({ global: true, wrap: true, forced: !NATIVE_SYMBOL, sham: !NATIVE_SYMBOL }, {
1907 $forEach$2(objectKeys$2(WellKnownSymbolsStore), function (name) {
1908 defineWellKnownSymbol$2(name);
1911 $$14({ target: SYMBOL, stat: true, forced: !NATIVE_SYMBOL }, {
1912 // `Symbol.for` method
1913 // https://tc39.es/ecma262/#sec-symbol.for
1914 'for': function (key) {
1915 var string = String(key);
1916 if (has$8(StringToSymbolRegistry, string)) return StringToSymbolRegistry[string];
1917 var symbol = $Symbol(string);
1918 StringToSymbolRegistry[string] = symbol;
1919 SymbolToStringRegistry[symbol] = string;
1922 // `Symbol.keyFor` method
1923 // https://tc39.es/ecma262/#sec-symbol.keyfor
1924 keyFor: function keyFor(sym) {
1925 if (!isSymbol$1(sym)) throw TypeError(sym + ' is not a symbol');
1926 if (has$8(SymbolToStringRegistry, sym)) return SymbolToStringRegistry[sym];
1928 useSetter: function () { USE_SETTER = true; },
1929 useSimple: function () { USE_SETTER = false; }
1932 $$14({ target: 'Object', stat: true, forced: !NATIVE_SYMBOL, sham: !DESCRIPTORS$h }, {
1933 // `Object.create` method
1934 // https://tc39.es/ecma262/#sec-object.create
1936 // `Object.defineProperty` method
1937 // https://tc39.es/ecma262/#sec-object.defineproperty
1938 defineProperty: $defineProperty,
1939 // `Object.defineProperties` method
1940 // https://tc39.es/ecma262/#sec-object.defineproperties
1941 defineProperties: $defineProperties,
1942 // `Object.getOwnPropertyDescriptor` method
1943 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptors
1944 getOwnPropertyDescriptor: $getOwnPropertyDescriptor
1947 $$14({ target: 'Object', stat: true, forced: !NATIVE_SYMBOL }, {
1948 // `Object.getOwnPropertyNames` method
1949 // https://tc39.es/ecma262/#sec-object.getownpropertynames
1950 getOwnPropertyNames: $getOwnPropertyNames,
1951 // `Object.getOwnPropertySymbols` method
1952 // https://tc39.es/ecma262/#sec-object.getownpropertysymbols
1953 getOwnPropertySymbols: $getOwnPropertySymbols
1956 // Chrome 38 and 39 `Object.getOwnPropertySymbols` fails on primitives
1957 // https://bugs.chromium.org/p/v8/issues/detail?id=3443
1958 $$14({ target: 'Object', stat: true, forced: fails$F(function () { getOwnPropertySymbolsModule$1.f(1); }) }, {
1959 getOwnPropertySymbols: function getOwnPropertySymbols(it) {
1960 return getOwnPropertySymbolsModule$1.f(toObject$e(it));
1964 // `JSON.stringify` method behavior with symbols
1965 // https://tc39.es/ecma262/#sec-json.stringify
1967 var FORCED_JSON_STRINGIFY = !NATIVE_SYMBOL || fails$F(function () {
1968 var symbol = $Symbol();
1969 // MS Edge converts symbol values to JSON as {}
1970 return $stringify([symbol]) != '[null]'
1971 // WebKit converts symbol values to JSON as null
1972 || $stringify({ a: symbol }) != '{}'
1973 // V8 throws on boxed symbols
1974 || $stringify(Object(symbol)) != '{}';
1977 $$14({ target: 'JSON', stat: true, forced: FORCED_JSON_STRINGIFY }, {
1978 // eslint-disable-next-line no-unused-vars -- required for `.length`
1979 stringify: function stringify(it, replacer, space) {
1983 while (arguments.length > index) args.push(arguments[index++]);
1984 $replacer = replacer;
1985 if (!isObject$k(replacer) && it === undefined || isSymbol$1(it)) return; // IE8 returns string on undefined
1986 if (!isArray$4(replacer)) replacer = function (key, value) {
1987 if (typeof $replacer == 'function') value = $replacer.call(this, key, value);
1988 if (!isSymbol$1(value)) return value;
1991 return $stringify.apply(null, args);
1996 // `Symbol.prototype[@@toPrimitive]` method
1997 // https://tc39.es/ecma262/#sec-symbol.prototype-@@toprimitive
1998 if (!$Symbol[PROTOTYPE$1][TO_PRIMITIVE]) {
1999 createNonEnumerableProperty$6($Symbol[PROTOTYPE$1], TO_PRIMITIVE, $Symbol[PROTOTYPE$1].valueOf);
2001 // `Symbol.prototype[@@toStringTag]` property
2002 // https://tc39.es/ecma262/#sec-symbol.prototype-@@tostringtag
2003 setToStringTag$7($Symbol, SYMBOL);
2005 hiddenKeys$1[HIDDEN] = true;
2008 var DESCRIPTORS$g = descriptors;
2009 var global$r = global$F;
2011 var isObject$j = isObject$r;
2012 var defineProperty$8 = objectDefineProperty.f;
2013 var copyConstructorProperties = copyConstructorProperties$2;
2015 var NativeSymbol = global$r.Symbol;
2017 if (DESCRIPTORS$g && typeof NativeSymbol == 'function' && (!('description' in NativeSymbol.prototype) ||
2019 NativeSymbol().description !== undefined
2021 var EmptyStringDescriptionStore = {};
2022 // wrap Symbol constructor for correct work with undefined description
2023 var SymbolWrapper = function Symbol() {
2024 var description = arguments.length < 1 || arguments[0] === undefined ? undefined : String(arguments[0]);
2025 var result = this instanceof SymbolWrapper
2026 ? new NativeSymbol(description)
2027 // in Edge 13, String(Symbol(undefined)) === 'Symbol(undefined)'
2028 : description === undefined ? NativeSymbol() : NativeSymbol(description);
2029 if (description === '') EmptyStringDescriptionStore[result] = true;
2032 copyConstructorProperties(SymbolWrapper, NativeSymbol);
2033 var symbolPrototype = SymbolWrapper.prototype = NativeSymbol.prototype;
2034 symbolPrototype.constructor = SymbolWrapper;
2036 var symbolToString = symbolPrototype.toString;
2037 var native = String(NativeSymbol('test')) == 'Symbol(test)';
2038 var regexp = /^Symbol\((.*)\)[^)]+$/;
2039 defineProperty$8(symbolPrototype, 'description', {
2041 get: function description() {
2042 var symbol = isObject$j(this) ? this.valueOf() : this;
2043 var string = symbolToString.call(symbol);
2044 if (has$7(EmptyStringDescriptionStore, symbol)) return '';
2045 var desc = native ? string.slice(7, -1) : string.replace(regexp, '$1');
2046 return desc === '' ? undefined : desc;
2050 $$13({ global: true, forced: true }, {
2051 Symbol: SymbolWrapper
2055 // eslint-disable-next-line es/no-typed-arrays -- safe
2056 var arrayBufferNative = typeof ArrayBuffer !== 'undefined' && typeof DataView !== 'undefined';
2058 var redefine$a = redefine$g.exports;
2060 var redefineAll$4 = function (target, src, options) {
2061 for (var key in src) redefine$a(target, key, src[key], options);
2065 var anInstance$7 = function (it, Constructor, name) {
2066 if (!(it instanceof Constructor)) {
2067 throw TypeError('Incorrect ' + (name ? name + ' ' : '') + 'invocation');
2071 var toInteger$7 = toInteger$b;
2072 var toLength$n = toLength$q;
2074 // `ToIndex` abstract operation
2075 // https://tc39.es/ecma262/#sec-toindex
2076 var toIndex$2 = function (it) {
2077 if (it === undefined) return 0;
2078 var number = toInteger$7(it);
2079 var length = toLength$n(number);
2080 if (number !== length) throw RangeError('Wrong length or index');
2084 // IEEE754 conversions based on https://github.com/feross/ieee754
2085 var abs$4 = Math.abs;
2086 var pow$2 = Math.pow;
2087 var floor$6 = Math.floor;
2088 var log$2 = Math.log;
2091 var pack = function (number, mantissaLength, bytes) {
2092 var buffer = new Array(bytes);
2093 var exponentLength = bytes * 8 - mantissaLength - 1;
2094 var eMax = (1 << exponentLength) - 1;
2095 var eBias = eMax >> 1;
2096 var rt = mantissaLength === 23 ? pow$2(2, -24) - pow$2(2, -77) : 0;
2097 var sign = number < 0 || number === 0 && 1 / number < 0 ? 1 : 0;
2099 var exponent, mantissa, c;
2100 number = abs$4(number);
2101 // eslint-disable-next-line no-self-compare -- NaN check
2102 if (number != number || number === Infinity) {
2103 // eslint-disable-next-line no-self-compare -- NaN check
2104 mantissa = number != number ? 1 : 0;
2107 exponent = floor$6(log$2(number) / LN2);
2108 if (number * (c = pow$2(2, -exponent)) < 1) {
2112 if (exponent + eBias >= 1) {
2115 number += rt * pow$2(2, 1 - eBias);
2117 if (number * c >= 2) {
2121 if (exponent + eBias >= eMax) {
2124 } else if (exponent + eBias >= 1) {
2125 mantissa = (number * c - 1) * pow$2(2, mantissaLength);
2126 exponent = exponent + eBias;
2128 mantissa = number * pow$2(2, eBias - 1) * pow$2(2, mantissaLength);
2132 for (; mantissaLength >= 8; buffer[index++] = mantissa & 255, mantissa /= 256, mantissaLength -= 8);
2133 exponent = exponent << mantissaLength | mantissa;
2134 exponentLength += mantissaLength;
2135 for (; exponentLength > 0; buffer[index++] = exponent & 255, exponent /= 256, exponentLength -= 8);
2136 buffer[--index] |= sign * 128;
2140 var unpack = function (buffer, mantissaLength) {
2141 var bytes = buffer.length;
2142 var exponentLength = bytes * 8 - mantissaLength - 1;
2143 var eMax = (1 << exponentLength) - 1;
2144 var eBias = eMax >> 1;
2145 var nBits = exponentLength - 7;
2146 var index = bytes - 1;
2147 var sign = buffer[index--];
2148 var exponent = sign & 127;
2151 for (; nBits > 0; exponent = exponent * 256 + buffer[index], index--, nBits -= 8);
2152 mantissa = exponent & (1 << -nBits) - 1;
2153 exponent >>= -nBits;
2154 nBits += mantissaLength;
2155 for (; nBits > 0; mantissa = mantissa * 256 + buffer[index], index--, nBits -= 8);
2156 if (exponent === 0) {
2157 exponent = 1 - eBias;
2158 } else if (exponent === eMax) {
2159 return mantissa ? NaN : sign ? -Infinity : Infinity;
2161 mantissa = mantissa + pow$2(2, mantissaLength);
2162 exponent = exponent - eBias;
2163 } return (sign ? -1 : 1) * mantissa * pow$2(2, exponent - mantissaLength);
2171 var toObject$d = toObject$i;
2172 var toAbsoluteIndex$6 = toAbsoluteIndex$8;
2173 var toLength$m = toLength$q;
2175 // `Array.prototype.fill` method implementation
2176 // https://tc39.es/ecma262/#sec-array.prototype.fill
2177 var arrayFill$1 = function fill(value /* , start = 0, end = @length */) {
2178 var O = toObject$d(this);
2179 var length = toLength$m(O.length);
2180 var argumentsLength = arguments.length;
2181 var index = toAbsoluteIndex$6(argumentsLength > 1 ? arguments[1] : undefined, length);
2182 var end = argumentsLength > 2 ? arguments[2] : undefined;
2183 var endPos = end === undefined ? length : toAbsoluteIndex$6(end, length);
2184 while (endPos > index) O[index++] = value;
2188 var global$q = global$F;
2189 var DESCRIPTORS$f = descriptors;
2190 var NATIVE_ARRAY_BUFFER$2 = arrayBufferNative;
2191 var createNonEnumerableProperty$5 = createNonEnumerableProperty$e;
2192 var redefineAll$3 = redefineAll$4;
2193 var fails$E = fails$N;
2194 var anInstance$6 = anInstance$7;
2195 var toInteger$6 = toInteger$b;
2196 var toLength$l = toLength$q;
2197 var toIndex$1 = toIndex$2;
2198 var IEEE754 = ieee754$2;
2199 var getPrototypeOf$2 = objectGetPrototypeOf;
2200 var setPrototypeOf$5 = objectSetPrototypeOf;
2201 var getOwnPropertyNames$4 = objectGetOwnPropertyNames.f;
2202 var defineProperty$7 = objectDefineProperty.f;
2203 var arrayFill = arrayFill$1;
2204 var setToStringTag$6 = setToStringTag$a;
2205 var InternalStateModule$5 = internalState;
2207 var getInternalState$3 = InternalStateModule$5.get;
2208 var setInternalState$5 = InternalStateModule$5.set;
2209 var ARRAY_BUFFER$1 = 'ArrayBuffer';
2210 var DATA_VIEW = 'DataView';
2211 var PROTOTYPE = 'prototype';
2212 var WRONG_LENGTH$1 = 'Wrong length';
2213 var WRONG_INDEX = 'Wrong index';
2214 var NativeArrayBuffer$1 = global$q[ARRAY_BUFFER$1];
2215 var $ArrayBuffer = NativeArrayBuffer$1;
2216 var $DataView = global$q[DATA_VIEW];
2217 var $DataViewPrototype = $DataView && $DataView[PROTOTYPE];
2218 var ObjectPrototype$1 = Object.prototype;
2219 var RangeError$2 = global$q.RangeError;
2221 var packIEEE754 = IEEE754.pack;
2222 var unpackIEEE754 = IEEE754.unpack;
2224 var packInt8 = function (number) {
2225 return [number & 0xFF];
2228 var packInt16 = function (number) {
2229 return [number & 0xFF, number >> 8 & 0xFF];
2232 var packInt32 = function (number) {
2233 return [number & 0xFF, number >> 8 & 0xFF, number >> 16 & 0xFF, number >> 24 & 0xFF];
2236 var unpackInt32 = function (buffer) {
2237 return buffer[3] << 24 | buffer[2] << 16 | buffer[1] << 8 | buffer[0];
2240 var packFloat32 = function (number) {
2241 return packIEEE754(number, 23, 4);
2244 var packFloat64 = function (number) {
2245 return packIEEE754(number, 52, 8);
2248 var addGetter$1 = function (Constructor, key) {
2249 defineProperty$7(Constructor[PROTOTYPE], key, { get: function () { return getInternalState$3(this)[key]; } });
2252 var get$4 = function (view, count, index, isLittleEndian) {
2253 var intIndex = toIndex$1(index);
2254 var store = getInternalState$3(view);
2255 if (intIndex + count > store.byteLength) throw RangeError$2(WRONG_INDEX);
2256 var bytes = getInternalState$3(store.buffer).bytes;
2257 var start = intIndex + store.byteOffset;
2258 var pack = bytes.slice(start, start + count);
2259 return isLittleEndian ? pack : pack.reverse();
2262 var set$3 = function (view, count, index, conversion, value, isLittleEndian) {
2263 var intIndex = toIndex$1(index);
2264 var store = getInternalState$3(view);
2265 if (intIndex + count > store.byteLength) throw RangeError$2(WRONG_INDEX);
2266 var bytes = getInternalState$3(store.buffer).bytes;
2267 var start = intIndex + store.byteOffset;
2268 var pack = conversion(+value);
2269 for (var i = 0; i < count; i++) bytes[start + i] = pack[isLittleEndian ? i : count - i - 1];
2272 if (!NATIVE_ARRAY_BUFFER$2) {
2273 $ArrayBuffer = function ArrayBuffer(length) {
2274 anInstance$6(this, $ArrayBuffer, ARRAY_BUFFER$1);
2275 var byteLength = toIndex$1(length);
2276 setInternalState$5(this, {
2277 bytes: arrayFill.call(new Array(byteLength), 0),
2278 byteLength: byteLength
2280 if (!DESCRIPTORS$f) this.byteLength = byteLength;
2283 $DataView = function DataView(buffer, byteOffset, byteLength) {
2284 anInstance$6(this, $DataView, DATA_VIEW);
2285 anInstance$6(buffer, $ArrayBuffer, DATA_VIEW);
2286 var bufferLength = getInternalState$3(buffer).byteLength;
2287 var offset = toInteger$6(byteOffset);
2288 if (offset < 0 || offset > bufferLength) throw RangeError$2('Wrong offset');
2289 byteLength = byteLength === undefined ? bufferLength - offset : toLength$l(byteLength);
2290 if (offset + byteLength > bufferLength) throw RangeError$2(WRONG_LENGTH$1);
2291 setInternalState$5(this, {
2293 byteLength: byteLength,
2296 if (!DESCRIPTORS$f) {
2297 this.buffer = buffer;
2298 this.byteLength = byteLength;
2299 this.byteOffset = offset;
2303 if (DESCRIPTORS$f) {
2304 addGetter$1($ArrayBuffer, 'byteLength');
2305 addGetter$1($DataView, 'buffer');
2306 addGetter$1($DataView, 'byteLength');
2307 addGetter$1($DataView, 'byteOffset');
2310 redefineAll$3($DataView[PROTOTYPE], {
2311 getInt8: function getInt8(byteOffset) {
2312 return get$4(this, 1, byteOffset)[0] << 24 >> 24;
2314 getUint8: function getUint8(byteOffset) {
2315 return get$4(this, 1, byteOffset)[0];
2317 getInt16: function getInt16(byteOffset /* , littleEndian */) {
2318 var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2319 return (bytes[1] << 8 | bytes[0]) << 16 >> 16;
2321 getUint16: function getUint16(byteOffset /* , littleEndian */) {
2322 var bytes = get$4(this, 2, byteOffset, arguments.length > 1 ? arguments[1] : undefined);
2323 return bytes[1] << 8 | bytes[0];
2325 getInt32: function getInt32(byteOffset /* , littleEndian */) {
2326 return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined));
2328 getUint32: function getUint32(byteOffset /* , littleEndian */) {
2329 return unpackInt32(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined)) >>> 0;
2331 getFloat32: function getFloat32(byteOffset /* , littleEndian */) {
2332 return unpackIEEE754(get$4(this, 4, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 23);
2334 getFloat64: function getFloat64(byteOffset /* , littleEndian */) {
2335 return unpackIEEE754(get$4(this, 8, byteOffset, arguments.length > 1 ? arguments[1] : undefined), 52);
2337 setInt8: function setInt8(byteOffset, value) {
2338 set$3(this, 1, byteOffset, packInt8, value);
2340 setUint8: function setUint8(byteOffset, value) {
2341 set$3(this, 1, byteOffset, packInt8, value);
2343 setInt16: function setInt16(byteOffset, value /* , littleEndian */) {
2344 set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2346 setUint16: function setUint16(byteOffset, value /* , littleEndian */) {
2347 set$3(this, 2, byteOffset, packInt16, value, arguments.length > 2 ? arguments[2] : undefined);
2349 setInt32: function setInt32(byteOffset, value /* , littleEndian */) {
2350 set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2352 setUint32: function setUint32(byteOffset, value /* , littleEndian */) {
2353 set$3(this, 4, byteOffset, packInt32, value, arguments.length > 2 ? arguments[2] : undefined);
2355 setFloat32: function setFloat32(byteOffset, value /* , littleEndian */) {
2356 set$3(this, 4, byteOffset, packFloat32, value, arguments.length > 2 ? arguments[2] : undefined);
2358 setFloat64: function setFloat64(byteOffset, value /* , littleEndian */) {
2359 set$3(this, 8, byteOffset, packFloat64, value, arguments.length > 2 ? arguments[2] : undefined);
2363 /* eslint-disable no-new -- required for testing */
2364 if (!fails$E(function () {
2365 NativeArrayBuffer$1(1);
2366 }) || !fails$E(function () {
2367 new NativeArrayBuffer$1(-1);
2368 }) || fails$E(function () {
2369 new NativeArrayBuffer$1();
2370 new NativeArrayBuffer$1(1.5);
2371 new NativeArrayBuffer$1(NaN);
2372 return NativeArrayBuffer$1.name != ARRAY_BUFFER$1;
2374 /* eslint-enable no-new -- required for testing */
2375 $ArrayBuffer = function ArrayBuffer(length) {
2376 anInstance$6(this, $ArrayBuffer);
2377 return new NativeArrayBuffer$1(toIndex$1(length));
2379 var ArrayBufferPrototype = $ArrayBuffer[PROTOTYPE] = NativeArrayBuffer$1[PROTOTYPE];
2380 for (var keys$2 = getOwnPropertyNames$4(NativeArrayBuffer$1), j$2 = 0, key$1; keys$2.length > j$2;) {
2381 if (!((key$1 = keys$2[j$2++]) in $ArrayBuffer)) {
2382 createNonEnumerableProperty$5($ArrayBuffer, key$1, NativeArrayBuffer$1[key$1]);
2385 ArrayBufferPrototype.constructor = $ArrayBuffer;
2388 // WebKit bug - the same parent prototype for typed arrays and data view
2389 if (setPrototypeOf$5 && getPrototypeOf$2($DataViewPrototype) !== ObjectPrototype$1) {
2390 setPrototypeOf$5($DataViewPrototype, ObjectPrototype$1);
2393 // iOS Safari 7.x bug
2394 var testView = new $DataView(new $ArrayBuffer(2));
2395 var $setInt8 = $DataViewPrototype.setInt8;
2396 testView.setInt8(0, 2147483648);
2397 testView.setInt8(1, 2147483649);
2398 if (testView.getInt8(0) || !testView.getInt8(1)) redefineAll$3($DataViewPrototype, {
2399 setInt8: function setInt8(byteOffset, value) {
2400 $setInt8.call(this, byteOffset, value << 24 >> 24);
2402 setUint8: function setUint8(byteOffset, value) {
2403 $setInt8.call(this, byteOffset, value << 24 >> 24);
2405 }, { unsafe: true });
2408 setToStringTag$6($ArrayBuffer, ARRAY_BUFFER$1);
2409 setToStringTag$6($DataView, DATA_VIEW);
2412 ArrayBuffer: $ArrayBuffer,
2416 var anObject$f = anObject$m;
2417 var aFunction$7 = aFunction$9;
2418 var wellKnownSymbol$h = wellKnownSymbol$s;
2420 var SPECIES$5 = wellKnownSymbol$h('species');
2422 // `SpeciesConstructor` abstract operation
2423 // https://tc39.es/ecma262/#sec-speciesconstructor
2424 var speciesConstructor$8 = function (O, defaultConstructor) {
2425 var C = anObject$f(O).constructor;
2427 return C === undefined || (S = anObject$f(C)[SPECIES$5]) == undefined ? defaultConstructor : aFunction$7(S);
2431 var fails$D = fails$N;
2432 var ArrayBufferModule$2 = arrayBuffer;
2433 var anObject$e = anObject$m;
2434 var toAbsoluteIndex$5 = toAbsoluteIndex$8;
2435 var toLength$k = toLength$q;
2436 var speciesConstructor$7 = speciesConstructor$8;
2438 var ArrayBuffer$4 = ArrayBufferModule$2.ArrayBuffer;
2439 var DataView$2 = ArrayBufferModule$2.DataView;
2440 var nativeArrayBufferSlice = ArrayBuffer$4.prototype.slice;
2442 var INCORRECT_SLICE = fails$D(function () {
2443 return !new ArrayBuffer$4(2).slice(1, undefined).byteLength;
2446 // `ArrayBuffer.prototype.slice` method
2447 // https://tc39.es/ecma262/#sec-arraybuffer.prototype.slice
2448 $$12({ target: 'ArrayBuffer', proto: true, unsafe: true, forced: INCORRECT_SLICE }, {
2449 slice: function slice(start, end) {
2450 if (nativeArrayBufferSlice !== undefined && end === undefined) {
2451 return nativeArrayBufferSlice.call(anObject$e(this), start); // FF fix
2453 var length = anObject$e(this).byteLength;
2454 var first = toAbsoluteIndex$5(start, length);
2455 var fin = toAbsoluteIndex$5(end === undefined ? length : end, length);
2456 var result = new (speciesConstructor$7(this, ArrayBuffer$4))(toLength$k(fin - first));
2457 var viewSource = new DataView$2(this);
2458 var viewTarget = new DataView$2(result);
2460 while (first < fin) {
2461 viewTarget.setUint8(index++, viewSource.getUint8(first++));
2467 var ArrayBufferModule$1 = arrayBuffer;
2468 var NATIVE_ARRAY_BUFFER$1 = arrayBufferNative;
2470 // `DataView` constructor
2471 // https://tc39.es/ecma262/#sec-dataview-constructor
2472 $$11({ global: true, forced: !NATIVE_ARRAY_BUFFER$1 }, {
2473 DataView: ArrayBufferModule$1.DataView
2476 var NATIVE_ARRAY_BUFFER = arrayBufferNative;
2477 var DESCRIPTORS$e = descriptors;
2478 var global$p = global$F;
2479 var isObject$i = isObject$r;
2481 var classof$8 = classof$b;
2482 var createNonEnumerableProperty$4 = createNonEnumerableProperty$e;
2483 var redefine$9 = redefine$g.exports;
2484 var defineProperty$6 = objectDefineProperty.f;
2485 var getPrototypeOf$1 = objectGetPrototypeOf;
2486 var setPrototypeOf$4 = objectSetPrototypeOf;
2487 var wellKnownSymbol$g = wellKnownSymbol$s;
2490 var Int8Array$3 = global$p.Int8Array;
2491 var Int8ArrayPrototype = Int8Array$3 && Int8Array$3.prototype;
2492 var Uint8ClampedArray = global$p.Uint8ClampedArray;
2493 var Uint8ClampedArrayPrototype = Uint8ClampedArray && Uint8ClampedArray.prototype;
2494 var TypedArray$1 = Int8Array$3 && getPrototypeOf$1(Int8Array$3);
2495 var TypedArrayPrototype$1 = Int8ArrayPrototype && getPrototypeOf$1(Int8ArrayPrototype);
2496 var ObjectPrototype = Object.prototype;
2497 var isPrototypeOf = ObjectPrototype.isPrototypeOf;
2499 var TO_STRING_TAG = wellKnownSymbol$g('toStringTag');
2500 var TYPED_ARRAY_TAG$1 = uid$1('TYPED_ARRAY_TAG');
2501 // Fixing native typed arrays in Opera Presto crashes the browser, see #595
2502 var NATIVE_ARRAY_BUFFER_VIEWS$3 = NATIVE_ARRAY_BUFFER && !!setPrototypeOf$4 && classof$8(global$p.opera) !== 'Opera';
2503 var TYPED_ARRAY_TAG_REQIRED = false;
2506 var TypedArrayConstructorsList = {
2509 Uint8ClampedArray: 1,
2518 var BigIntArrayConstructorsList = {
2523 var isView = function isView(it) {
2524 if (!isObject$i(it)) return false;
2525 var klass = classof$8(it);
2526 return klass === 'DataView'
2527 || has$6(TypedArrayConstructorsList, klass)
2528 || has$6(BigIntArrayConstructorsList, klass);
2531 var isTypedArray$1 = function (it) {
2532 if (!isObject$i(it)) return false;
2533 var klass = classof$8(it);
2534 return has$6(TypedArrayConstructorsList, klass)
2535 || has$6(BigIntArrayConstructorsList, klass);
2538 var aTypedArray$m = function (it) {
2539 if (isTypedArray$1(it)) return it;
2540 throw TypeError('Target is not a typed array');
2543 var aTypedArrayConstructor$5 = function (C) {
2544 if (setPrototypeOf$4) {
2545 if (isPrototypeOf.call(TypedArray$1, C)) return C;
2546 } else for (var ARRAY in TypedArrayConstructorsList) if (has$6(TypedArrayConstructorsList, NAME$1)) {
2547 var TypedArrayConstructor = global$p[ARRAY];
2548 if (TypedArrayConstructor && (C === TypedArrayConstructor || isPrototypeOf.call(TypedArrayConstructor, C))) {
2551 } throw TypeError('Target is not a typed array constructor');
2554 var exportTypedArrayMethod$n = function (KEY, property, forced) {
2555 if (!DESCRIPTORS$e) return;
2556 if (forced) for (var ARRAY in TypedArrayConstructorsList) {
2557 var TypedArrayConstructor = global$p[ARRAY];
2558 if (TypedArrayConstructor && has$6(TypedArrayConstructor.prototype, KEY)) try {
2559 delete TypedArrayConstructor.prototype[KEY];
2560 } catch (error) { /* empty */ }
2562 if (!TypedArrayPrototype$1[KEY] || forced) {
2563 redefine$9(TypedArrayPrototype$1, KEY, forced ? property
2564 : NATIVE_ARRAY_BUFFER_VIEWS$3 && Int8ArrayPrototype[KEY] || property);
2568 var exportTypedArrayStaticMethod$1 = function (KEY, property, forced) {
2569 var ARRAY, TypedArrayConstructor;
2570 if (!DESCRIPTORS$e) return;
2571 if (setPrototypeOf$4) {
2572 if (forced) for (ARRAY in TypedArrayConstructorsList) {
2573 TypedArrayConstructor = global$p[ARRAY];
2574 if (TypedArrayConstructor && has$6(TypedArrayConstructor, KEY)) try {
2575 delete TypedArrayConstructor[KEY];
2576 } catch (error) { /* empty */ }
2578 if (!TypedArray$1[KEY] || forced) {
2579 // V8 ~ Chrome 49-50 `%TypedArray%` methods are non-writable non-configurable
2581 return redefine$9(TypedArray$1, KEY, forced ? property : NATIVE_ARRAY_BUFFER_VIEWS$3 && TypedArray$1[KEY] || property);
2582 } catch (error) { /* empty */ }
2585 for (ARRAY in TypedArrayConstructorsList) {
2586 TypedArrayConstructor = global$p[ARRAY];
2587 if (TypedArrayConstructor && (!TypedArrayConstructor[KEY] || forced)) {
2588 redefine$9(TypedArrayConstructor, KEY, property);
2593 for (NAME$1 in TypedArrayConstructorsList) {
2594 if (!global$p[NAME$1]) NATIVE_ARRAY_BUFFER_VIEWS$3 = false;
2597 // WebKit bug - typed arrays constructors prototype is Object.prototype
2598 if (!NATIVE_ARRAY_BUFFER_VIEWS$3 || typeof TypedArray$1 != 'function' || TypedArray$1 === Function.prototype) {
2599 // eslint-disable-next-line no-shadow -- safe
2600 TypedArray$1 = function TypedArray() {
2601 throw TypeError('Incorrect invocation');
2603 if (NATIVE_ARRAY_BUFFER_VIEWS$3) for (NAME$1 in TypedArrayConstructorsList) {
2604 if (global$p[NAME$1]) setPrototypeOf$4(global$p[NAME$1], TypedArray$1);
2608 if (!NATIVE_ARRAY_BUFFER_VIEWS$3 || !TypedArrayPrototype$1 || TypedArrayPrototype$1 === ObjectPrototype) {
2609 TypedArrayPrototype$1 = TypedArray$1.prototype;
2610 if (NATIVE_ARRAY_BUFFER_VIEWS$3) for (NAME$1 in TypedArrayConstructorsList) {
2611 if (global$p[NAME$1]) setPrototypeOf$4(global$p[NAME$1].prototype, TypedArrayPrototype$1);
2615 // WebKit bug - one more object in Uint8ClampedArray prototype chain
2616 if (NATIVE_ARRAY_BUFFER_VIEWS$3 && getPrototypeOf$1(Uint8ClampedArrayPrototype) !== TypedArrayPrototype$1) {
2617 setPrototypeOf$4(Uint8ClampedArrayPrototype, TypedArrayPrototype$1);
2620 if (DESCRIPTORS$e && !has$6(TypedArrayPrototype$1, TO_STRING_TAG)) {
2621 TYPED_ARRAY_TAG_REQIRED = true;
2622 defineProperty$6(TypedArrayPrototype$1, TO_STRING_TAG, { get: function () {
2623 return isObject$i(this) ? this[TYPED_ARRAY_TAG$1] : undefined;
2625 for (NAME$1 in TypedArrayConstructorsList) if (global$p[NAME$1]) {
2626 createNonEnumerableProperty$4(global$p[NAME$1], TYPED_ARRAY_TAG$1, NAME$1);
2630 var arrayBufferViewCore = {
2631 NATIVE_ARRAY_BUFFER_VIEWS: NATIVE_ARRAY_BUFFER_VIEWS$3,
2632 TYPED_ARRAY_TAG: TYPED_ARRAY_TAG_REQIRED && TYPED_ARRAY_TAG$1,
2633 aTypedArray: aTypedArray$m,
2634 aTypedArrayConstructor: aTypedArrayConstructor$5,
2635 exportTypedArrayMethod: exportTypedArrayMethod$n,
2636 exportTypedArrayStaticMethod: exportTypedArrayStaticMethod$1,
2638 isTypedArray: isTypedArray$1,
2639 TypedArray: TypedArray$1,
2640 TypedArrayPrototype: TypedArrayPrototype$1
2644 var ArrayBufferViewCore$n = arrayBufferViewCore;
2646 var NATIVE_ARRAY_BUFFER_VIEWS$2 = ArrayBufferViewCore$n.NATIVE_ARRAY_BUFFER_VIEWS;
2648 // `ArrayBuffer.isView` method
2649 // https://tc39.es/ecma262/#sec-arraybuffer.isview
2650 $$10({ target: 'ArrayBuffer', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS$2 }, {
2651 isView: ArrayBufferViewCore$n.isView
2654 var getBuiltIn$4 = getBuiltIn$9;
2655 var definePropertyModule$2 = objectDefineProperty;
2656 var wellKnownSymbol$f = wellKnownSymbol$s;
2657 var DESCRIPTORS$d = descriptors;
2659 var SPECIES$4 = wellKnownSymbol$f('species');
2661 var setSpecies$5 = function (CONSTRUCTOR_NAME) {
2662 var Constructor = getBuiltIn$4(CONSTRUCTOR_NAME);
2663 var defineProperty = definePropertyModule$2.f;
2665 if (DESCRIPTORS$d && Constructor && !Constructor[SPECIES$4]) {
2666 defineProperty(Constructor, SPECIES$4, {
2668 get: function () { return this; }
2674 var global$o = global$F;
2675 var arrayBufferModule = arrayBuffer;
2676 var setSpecies$4 = setSpecies$5;
2678 var ARRAY_BUFFER = 'ArrayBuffer';
2679 var ArrayBuffer$3 = arrayBufferModule[ARRAY_BUFFER];
2680 var NativeArrayBuffer = global$o[ARRAY_BUFFER];
2682 // `ArrayBuffer` constructor
2683 // https://tc39.es/ecma262/#sec-arraybuffer-constructor
2684 $$$({ global: true, forced: NativeArrayBuffer !== ArrayBuffer$3 }, {
2685 ArrayBuffer: ArrayBuffer$3
2688 setSpecies$4(ARRAY_BUFFER);
2690 var fails$C = fails$N;
2692 var arrayMethodIsStrict$8 = function (METHOD_NAME, argument) {
2693 var method = [][METHOD_NAME];
2694 return !!method && fails$C(function () {
2695 // eslint-disable-next-line no-useless-call,no-throw-literal -- required for testing
2696 method.call(null, argument || function () { throw 1; }, 1);
2700 /* eslint-disable es/no-array-prototype-indexof -- required for testing */
2702 var $indexOf$1 = arrayIncludes.indexOf;
2703 var arrayMethodIsStrict$7 = arrayMethodIsStrict$8;
2705 var nativeIndexOf = [].indexOf;
2707 var NEGATIVE_ZERO$1 = !!nativeIndexOf && 1 / [1].indexOf(1, -0) < 0;
2708 var STRICT_METHOD$7 = arrayMethodIsStrict$7('indexOf');
2710 // `Array.prototype.indexOf` method
2711 // https://tc39.es/ecma262/#sec-array.prototype.indexof
2712 $$_({ target: 'Array', proto: true, forced: NEGATIVE_ZERO$1 || !STRICT_METHOD$7 }, {
2713 indexOf: function indexOf(searchElement /* , fromIndex = 0 */) {
2714 return NEGATIVE_ZERO$1
2716 ? nativeIndexOf.apply(this, arguments) || 0
2717 : $indexOf$1(this, searchElement, arguments.length > 1 ? arguments[1] : undefined);
2721 var fails$B = fails$N;
2722 var wellKnownSymbol$e = wellKnownSymbol$s;
2723 var V8_VERSION$2 = engineV8Version;
2725 var SPECIES$3 = wellKnownSymbol$e('species');
2727 var arrayMethodHasSpeciesSupport$5 = function (METHOD_NAME) {
2728 // We can't use this feature detection in V8 since it causes
2729 // deoptimization and serious performance degradation
2730 // https://github.com/zloirock/core-js/issues/677
2731 return V8_VERSION$2 >= 51 || !fails$B(function () {
2733 var constructor = array.constructor = {};
2734 constructor[SPECIES$3] = function () {
2737 return array[METHOD_NAME](Boolean).foo !== 1;
2742 var $map$1 = arrayIteration.map;
2743 var arrayMethodHasSpeciesSupport$4 = arrayMethodHasSpeciesSupport$5;
2745 var HAS_SPECIES_SUPPORT$3 = arrayMethodHasSpeciesSupport$4('map');
2747 // `Array.prototype.map` method
2748 // https://tc39.es/ecma262/#sec-array.prototype.map
2749 // with adding support of @@species
2750 $$Z({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$3 }, {
2751 map: function map(callbackfn /* , thisArg */) {
2752 return $map$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2756 var $forEach$1 = arrayIteration.forEach;
2757 var arrayMethodIsStrict$6 = arrayMethodIsStrict$8;
2759 var STRICT_METHOD$6 = arrayMethodIsStrict$6('forEach');
2761 // `Array.prototype.forEach` method implementation
2762 // https://tc39.es/ecma262/#sec-array.prototype.foreach
2763 var arrayForEach = !STRICT_METHOD$6 ? function forEach(callbackfn /* , thisArg */) {
2764 return $forEach$1(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
2765 // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2769 var forEach$3 = arrayForEach;
2771 // `Array.prototype.forEach` method
2772 // https://tc39.es/ecma262/#sec-array.prototype.foreach
2773 // eslint-disable-next-line es/no-array-prototype-foreach -- safe
2774 $$Y({ target: 'Array', proto: true, forced: [].forEach != forEach$3 }, {
2778 var global$n = global$F;
2779 var DOMIterables = domIterables;
2780 var forEach$2 = arrayForEach;
2781 var createNonEnumerableProperty$3 = createNonEnumerableProperty$e;
2783 for (var COLLECTION_NAME in DOMIterables) {
2784 var Collection = global$n[COLLECTION_NAME];
2785 var CollectionPrototype = Collection && Collection.prototype;
2786 // some Chrome versions have non-configurable methods on DOMTokenList
2787 if (CollectionPrototype && CollectionPrototype.forEach !== forEach$2) try {
2788 createNonEnumerableProperty$3(CollectionPrototype, 'forEach', forEach$2);
2790 CollectionPrototype.forEach = forEach$2;
2795 var isArray$3 = isArray$6;
2797 // `Array.isArray` method
2798 // https://tc39.es/ecma262/#sec-array.isarray
2799 $$X({ target: 'Array', stat: true }, {
2804 var fails$A = fails$N;
2805 var getOwnPropertyNames$3 = objectGetOwnPropertyNamesExternal.f;
2807 // eslint-disable-next-line es/no-object-getownpropertynames -- required for testing
2808 var FAILS_ON_PRIMITIVES$4 = fails$A(function () { return !Object.getOwnPropertyNames(1); });
2810 // `Object.getOwnPropertyNames` method
2811 // https://tc39.es/ecma262/#sec-object.getownpropertynames
2812 $$W({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$4 }, {
2813 getOwnPropertyNames: getOwnPropertyNames$3
2816 var global$m = global$F;
2818 var nativePromiseConstructor = global$m.Promise;
2820 var wellKnownSymbol$d = wellKnownSymbol$s;
2821 var Iterators$1 = iterators;
2823 var ITERATOR$5 = wellKnownSymbol$d('iterator');
2824 var ArrayPrototype = Array.prototype;
2826 // check on default Array iterator
2827 var isArrayIteratorMethod$3 = function (it) {
2828 return it !== undefined && (Iterators$1.Array === it || ArrayPrototype[ITERATOR$5] === it);
2831 var classof$7 = classof$b;
2832 var Iterators = iterators;
2833 var wellKnownSymbol$c = wellKnownSymbol$s;
2835 var ITERATOR$4 = wellKnownSymbol$c('iterator');
2837 var getIteratorMethod$5 = function (it) {
2838 if (it != undefined) return it[ITERATOR$4]
2840 || Iterators[classof$7(it)];
2843 var anObject$d = anObject$m;
2845 var iteratorClose$2 = function (iterator) {
2846 var returnMethod = iterator['return'];
2847 if (returnMethod !== undefined) {
2848 return anObject$d(returnMethod.call(iterator)).value;
2852 var anObject$c = anObject$m;
2853 var isArrayIteratorMethod$2 = isArrayIteratorMethod$3;
2854 var toLength$j = toLength$q;
2855 var bind$a = functionBindContext;
2856 var getIteratorMethod$4 = getIteratorMethod$5;
2857 var iteratorClose$1 = iteratorClose$2;
2859 var Result = function (stopped, result) {
2860 this.stopped = stopped;
2861 this.result = result;
2864 var iterate$3 = function (iterable, unboundFunction, options) {
2865 var that = options && options.that;
2866 var AS_ENTRIES = !!(options && options.AS_ENTRIES);
2867 var IS_ITERATOR = !!(options && options.IS_ITERATOR);
2868 var INTERRUPTED = !!(options && options.INTERRUPTED);
2869 var fn = bind$a(unboundFunction, that, 1 + AS_ENTRIES + INTERRUPTED);
2870 var iterator, iterFn, index, length, result, next, step;
2872 var stop = function (condition) {
2873 if (iterator) iteratorClose$1(iterator);
2874 return new Result(true, condition);
2877 var callFn = function (value) {
2880 return INTERRUPTED ? fn(value[0], value[1], stop) : fn(value[0], value[1]);
2881 } return INTERRUPTED ? fn(value, stop) : fn(value);
2885 iterator = iterable;
2887 iterFn = getIteratorMethod$4(iterable);
2888 if (typeof iterFn != 'function') throw TypeError('Target is not iterable');
2889 // optimisation for array iterators
2890 if (isArrayIteratorMethod$2(iterFn)) {
2891 for (index = 0, length = toLength$j(iterable.length); length > index; index++) {
2892 result = callFn(iterable[index]);
2893 if (result && result instanceof Result) return result;
2894 } return new Result(false);
2896 iterator = iterFn.call(iterable);
2899 next = iterator.next;
2900 while (!(step = next.call(iterator)).done) {
2902 result = callFn(step.value);
2904 iteratorClose$1(iterator);
2907 if (typeof result == 'object' && result && result instanceof Result) return result;
2908 } return new Result(false);
2911 var wellKnownSymbol$b = wellKnownSymbol$s;
2913 var ITERATOR$3 = wellKnownSymbol$b('iterator');
2914 var SAFE_CLOSING = false;
2918 var iteratorWithReturn = {
2920 return { done: !!called++ };
2922 'return': function () {
2923 SAFE_CLOSING = true;
2926 iteratorWithReturn[ITERATOR$3] = function () {
2929 // eslint-disable-next-line es/no-array-from, no-throw-literal -- required for testing
2930 Array.from(iteratorWithReturn, function () { throw 2; });
2931 } catch (error) { /* empty */ }
2933 var checkCorrectnessOfIteration$4 = function (exec, SKIP_CLOSING) {
2934 if (!SKIP_CLOSING && !SAFE_CLOSING) return false;
2935 var ITERATION_SUPPORT = false;
2938 object[ITERATOR$3] = function () {
2941 return { done: ITERATION_SUPPORT = true };
2946 } catch (error) { /* empty */ }
2947 return ITERATION_SUPPORT;
2950 var userAgent$4 = engineUserAgent;
2952 var engineIsIos = /(?:iphone|ipod|ipad).*applewebkit/i.test(userAgent$4);
2954 var classof$6 = classofRaw$1;
2955 var global$l = global$F;
2957 var engineIsNode = classof$6(global$l.process) == 'process';
2959 var global$k = global$F;
2960 var fails$z = fails$N;
2961 var bind$9 = functionBindContext;
2963 var createElement = documentCreateElement$1;
2964 var IS_IOS$1 = engineIsIos;
2965 var IS_NODE$3 = engineIsNode;
2967 var location$1 = global$k.location;
2968 var set$2 = global$k.setImmediate;
2969 var clear = global$k.clearImmediate;
2970 var process$3 = global$k.process;
2971 var MessageChannel = global$k.MessageChannel;
2972 var Dispatch$1 = global$k.Dispatch;
2975 var ONREADYSTATECHANGE = 'onreadystatechange';
2976 var defer, channel, port;
2978 var run = function (id) {
2979 // eslint-disable-next-line no-prototype-builtins -- safe
2980 if (queue.hasOwnProperty(id)) {
2987 var runner = function (id) {
2988 return function () {
2993 var listener = function (event) {
2997 var post = function (id) {
2998 // old engines have not location.origin
2999 global$k.postMessage(id + '', location$1.protocol + '//' + location$1.host);
3002 // Node.js 0.9+ & IE10+ has setImmediate, otherwise:
3003 if (!set$2 || !clear) {
3004 set$2 = function setImmediate(fn) {
3007 while (arguments.length > i) args.push(arguments[i++]);
3008 queue[++counter] = function () {
3009 // eslint-disable-next-line no-new-func -- spec requirement
3010 (typeof fn == 'function' ? fn : Function(fn)).apply(undefined, args);
3015 clear = function clearImmediate(id) {
3020 defer = function (id) {
3021 process$3.nextTick(runner(id));
3023 // Sphere (JS game engine) Dispatch API
3024 } else if (Dispatch$1 && Dispatch$1.now) {
3025 defer = function (id) {
3026 Dispatch$1.now(runner(id));
3028 // Browsers with MessageChannel, includes WebWorkers
3029 // except iOS - https://github.com/zloirock/core-js/issues/624
3030 } else if (MessageChannel && !IS_IOS$1) {
3031 channel = new MessageChannel();
3032 port = channel.port2;
3033 channel.port1.onmessage = listener;
3034 defer = bind$9(port.postMessage, port, 1);
3035 // Browsers with postMessage, skip WebWorkers
3036 // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
3038 global$k.addEventListener &&
3039 typeof postMessage == 'function' &&
3040 !global$k.importScripts &&
3041 location$1 && location$1.protocol !== 'file:' &&
3045 global$k.addEventListener('message', listener, false);
3047 } else if (ONREADYSTATECHANGE in createElement('script')) {
3048 defer = function (id) {
3049 html.appendChild(createElement('script'))[ONREADYSTATECHANGE] = function () {
3050 html.removeChild(this);
3054 // Rest old browsers
3056 defer = function (id) {
3057 setTimeout(runner(id), 0);
3067 var userAgent$3 = engineUserAgent;
3069 var engineIsWebosWebkit = /web0s(?!.*chrome)/i.test(userAgent$3);
3071 var global$j = global$F;
3072 var getOwnPropertyDescriptor$3 = objectGetOwnPropertyDescriptor.f;
3073 var macrotask = task$1.set;
3074 var IS_IOS = engineIsIos;
3075 var IS_WEBOS_WEBKIT = engineIsWebosWebkit;
3076 var IS_NODE$2 = engineIsNode;
3078 var MutationObserver = global$j.MutationObserver || global$j.WebKitMutationObserver;
3079 var document$2 = global$j.document;
3080 var process$2 = global$j.process;
3081 var Promise$1 = global$j.Promise;
3082 // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
3083 var queueMicrotaskDescriptor = getOwnPropertyDescriptor$3(global$j, 'queueMicrotask');
3084 var queueMicrotask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
3086 var flush, head, last, notify$1, toggle, node, promise, then;
3088 // modern engines have queueMicrotask method
3089 if (!queueMicrotask) {
3090 flush = function () {
3092 if (IS_NODE$2 && (parent = process$2.domain)) parent.exit();
3099 if (head) notify$1();
3100 else last = undefined;
3104 if (parent) parent.enter();
3107 // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
3108 // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
3109 if (!IS_IOS && !IS_NODE$2 && !IS_WEBOS_WEBKIT && MutationObserver && document$2) {
3111 node = document$2.createTextNode('');
3112 new MutationObserver(flush).observe(node, { characterData: true });
3113 notify$1 = function () {
3114 node.data = toggle = !toggle;
3116 // environments with maybe non-completely correct, but existent Promise
3117 } else if (Promise$1 && Promise$1.resolve) {
3118 // Promise.resolve without an argument throws an error in LG WebOS 2
3119 promise = Promise$1.resolve(undefined);
3120 // workaround of WebKit ~ iOS Safari 10.1 bug
3121 promise.constructor = Promise$1;
3122 then = promise.then;
3123 notify$1 = function () {
3124 then.call(promise, flush);
3126 // Node.js without promises
3127 } else if (IS_NODE$2) {
3128 notify$1 = function () {
3129 process$2.nextTick(flush);
3131 // for other environments - macrotask based on:
3134 // - window.postMessag
3135 // - onreadystatechange
3138 notify$1 = function () {
3139 // strange IE + webpack dev server bug - use .call(global)
3140 macrotask.call(global$j, flush);
3145 var microtask$1 = queueMicrotask || function (fn) {
3146 var task = { fn: fn, next: undefined };
3147 if (last) last.next = task;
3154 var newPromiseCapability$2 = {};
3156 var aFunction$6 = aFunction$9;
3158 var PromiseCapability = function (C) {
3159 var resolve, reject;
3160 this.promise = new C(function ($$resolve, $$reject) {
3161 if (resolve !== undefined || reject !== undefined) throw TypeError('Bad Promise constructor');
3162 resolve = $$resolve;
3165 this.resolve = aFunction$6(resolve);
3166 this.reject = aFunction$6(reject);
3169 // `NewPromiseCapability` abstract operation
3170 // https://tc39.es/ecma262/#sec-newpromisecapability
3171 newPromiseCapability$2.f = function (C) {
3172 return new PromiseCapability(C);
3175 var anObject$b = anObject$m;
3176 var isObject$h = isObject$r;
3177 var newPromiseCapability$1 = newPromiseCapability$2;
3179 var promiseResolve$2 = function (C, x) {
3181 if (isObject$h(x) && x.constructor === C) return x;
3182 var promiseCapability = newPromiseCapability$1.f(C);
3183 var resolve = promiseCapability.resolve;
3185 return promiseCapability.promise;
3188 var global$i = global$F;
3190 var hostReportErrors$1 = function (a, b) {
3191 var console = global$i.console;
3192 if (console && console.error) {
3193 arguments.length === 1 ? console.error(a) : console.error(a, b);
3197 var perform$1 = function (exec) {
3199 return { error: false, value: exec() };
3201 return { error: true, value: error };
3205 var engineIsBrowser = typeof window == 'object';
3208 var global$h = global$F;
3209 var getBuiltIn$3 = getBuiltIn$9;
3210 var NativePromise$1 = nativePromiseConstructor;
3211 var redefine$8 = redefine$g.exports;
3212 var redefineAll$2 = redefineAll$4;
3213 var setPrototypeOf$3 = objectSetPrototypeOf;
3214 var setToStringTag$5 = setToStringTag$a;
3215 var setSpecies$3 = setSpecies$5;
3216 var isObject$g = isObject$r;
3217 var aFunction$5 = aFunction$9;
3218 var anInstance$5 = anInstance$7;
3219 var inspectSource = inspectSource$3;
3220 var iterate$2 = iterate$3;
3221 var checkCorrectnessOfIteration$3 = checkCorrectnessOfIteration$4;
3222 var speciesConstructor$6 = speciesConstructor$8;
3223 var task = task$1.set;
3224 var microtask = microtask$1;
3225 var promiseResolve$1 = promiseResolve$2;
3226 var hostReportErrors = hostReportErrors$1;
3227 var newPromiseCapabilityModule = newPromiseCapability$2;
3228 var perform = perform$1;
3229 var InternalStateModule$4 = internalState;
3230 var isForced$3 = isForced_1;
3231 var wellKnownSymbol$a = wellKnownSymbol$s;
3232 var IS_BROWSER = engineIsBrowser;
3233 var IS_NODE$1 = engineIsNode;
3234 var V8_VERSION$1 = engineV8Version;
3236 var SPECIES$2 = wellKnownSymbol$a('species');
3237 var PROMISE = 'Promise';
3238 var getInternalState$2 = InternalStateModule$4.get;
3239 var setInternalState$4 = InternalStateModule$4.set;
3240 var getInternalPromiseState = InternalStateModule$4.getterFor(PROMISE);
3241 var NativePromisePrototype = NativePromise$1 && NativePromise$1.prototype;
3242 var PromiseConstructor = NativePromise$1;
3243 var PromiseConstructorPrototype = NativePromisePrototype;
3244 var TypeError$1 = global$h.TypeError;
3245 var document$1 = global$h.document;
3246 var process$1 = global$h.process;
3247 var newPromiseCapability = newPromiseCapabilityModule.f;
3248 var newGenericPromiseCapability = newPromiseCapability;
3249 var DISPATCH_EVENT = !!(document$1 && document$1.createEvent && global$h.dispatchEvent);
3250 var NATIVE_REJECTION_EVENT = typeof PromiseRejectionEvent == 'function';
3251 var UNHANDLED_REJECTION = 'unhandledrejection';
3252 var REJECTION_HANDLED = 'rejectionhandled';
3258 var SUBCLASSING = false;
3259 var Internal, OwnPromiseCapability, PromiseWrapper, nativeThen;
3261 var FORCED$f = isForced$3(PROMISE, function () {
3262 var GLOBAL_CORE_JS_PROMISE = inspectSource(PromiseConstructor) !== String(PromiseConstructor);
3263 // V8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
3264 // https://bugs.chromium.org/p/chromium/issues/detail?id=830565
3265 // We can't detect it synchronously, so just check versions
3266 if (!GLOBAL_CORE_JS_PROMISE && V8_VERSION$1 === 66) return true;
3267 // We can't use @@species feature detection in V8 since it causes
3268 // deoptimization and performance degradation
3269 // https://github.com/zloirock/core-js/issues/679
3270 if (V8_VERSION$1 >= 51 && /native code/.test(PromiseConstructor)) return false;
3271 // Detect correctness of subclassing with @@species support
3272 var promise = new PromiseConstructor(function (resolve) { resolve(1); });
3273 var FakePromise = function (exec) {
3274 exec(function () { /* empty */ }, function () { /* empty */ });
3276 var constructor = promise.constructor = {};
3277 constructor[SPECIES$2] = FakePromise;
3278 SUBCLASSING = promise.then(function () { /* empty */ }) instanceof FakePromise;
3279 if (!SUBCLASSING) return true;
3280 // Unhandled rejections tracking support, NodeJS Promise without it fails @@species test
3281 return !GLOBAL_CORE_JS_PROMISE && IS_BROWSER && !NATIVE_REJECTION_EVENT;
3284 var INCORRECT_ITERATION$1 = FORCED$f || !checkCorrectnessOfIteration$3(function (iterable) {
3285 PromiseConstructor.all(iterable)['catch'](function () { /* empty */ });
3289 var isThenable = function (it) {
3291 return isObject$g(it) && typeof (then = it.then) == 'function' ? then : false;
3294 var notify = function (state, isReject) {
3295 if (state.notified) return;
3296 state.notified = true;
3297 var chain = state.reactions;
3298 microtask(function () {
3299 var value = state.value;
3300 var ok = state.state == FULFILLED;
3302 // variable length - can't use forEach
3303 while (chain.length > index) {
3304 var reaction = chain[index++];
3305 var handler = ok ? reaction.ok : reaction.fail;
3306 var resolve = reaction.resolve;
3307 var reject = reaction.reject;
3308 var domain = reaction.domain;
3309 var result, then, exited;
3313 if (state.rejection === UNHANDLED) onHandleUnhandled(state);
3314 state.rejection = HANDLED;
3316 if (handler === true) result = value;
3318 if (domain) domain.enter();
3319 result = handler(value); // can throw
3325 if (result === reaction.promise) {
3326 reject(TypeError$1('Promise-chain cycle'));
3327 } else if (then = isThenable(result)) {
3328 then.call(result, resolve, reject);
3329 } else resolve(result);
3330 } else reject(value);
3332 if (domain && !exited) domain.exit();
3336 state.reactions = [];
3337 state.notified = false;
3338 if (isReject && !state.rejection) onUnhandled(state);
3342 var dispatchEvent$1 = function (name, promise, reason) {
3344 if (DISPATCH_EVENT) {
3345 event = document$1.createEvent('Event');
3346 event.promise = promise;
3347 event.reason = reason;
3348 event.initEvent(name, false, true);
3349 global$h.dispatchEvent(event);
3350 } else event = { promise: promise, reason: reason };
3351 if (!NATIVE_REJECTION_EVENT && (handler = global$h['on' + name])) handler(event);
3352 else if (name === UNHANDLED_REJECTION) hostReportErrors('Unhandled promise rejection', reason);
3355 var onUnhandled = function (state) {
3356 task.call(global$h, function () {
3357 var promise = state.facade;
3358 var value = state.value;
3359 var IS_UNHANDLED = isUnhandled(state);
3362 result = perform(function () {
3364 process$1.emit('unhandledRejection', value, promise);
3365 } else dispatchEvent$1(UNHANDLED_REJECTION, promise, value);
3367 // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
3368 state.rejection = IS_NODE$1 || isUnhandled(state) ? UNHANDLED : HANDLED;
3369 if (result.error) throw result.value;
3374 var isUnhandled = function (state) {
3375 return state.rejection !== HANDLED && !state.parent;
3378 var onHandleUnhandled = function (state) {
3379 task.call(global$h, function () {
3380 var promise = state.facade;
3382 process$1.emit('rejectionHandled', promise);
3383 } else dispatchEvent$1(REJECTION_HANDLED, promise, state.value);
3387 var bind$8 = function (fn, state, unwrap) {
3388 return function (value) {
3389 fn(state, value, unwrap);
3393 var internalReject = function (state, value, unwrap) {
3394 if (state.done) return;
3396 if (unwrap) state = unwrap;
3397 state.value = value;
3398 state.state = REJECTED;
3399 notify(state, true);
3402 var internalResolve = function (state, value, unwrap) {
3403 if (state.done) return;
3405 if (unwrap) state = unwrap;
3407 if (state.facade === value) throw TypeError$1("Promise can't be resolved itself");
3408 var then = isThenable(value);
3410 microtask(function () {
3411 var wrapper = { done: false };
3414 bind$8(internalResolve, wrapper, state),
3415 bind$8(internalReject, wrapper, state)
3418 internalReject(wrapper, error, state);
3422 state.value = value;
3423 state.state = FULFILLED;
3424 notify(state, false);
3427 internalReject({ done: false }, error, state);
3431 // constructor polyfill
3433 // 25.4.3.1 Promise(executor)
3434 PromiseConstructor = function Promise(executor) {
3435 anInstance$5(this, PromiseConstructor, PROMISE);
3436 aFunction$5(executor);
3437 Internal.call(this);
3438 var state = getInternalState$2(this);
3440 executor(bind$8(internalResolve, state), bind$8(internalReject, state));
3442 internalReject(state, error);
3445 PromiseConstructorPrototype = PromiseConstructor.prototype;
3446 // eslint-disable-next-line no-unused-vars -- required for `.length`
3447 Internal = function Promise(executor) {
3448 setInternalState$4(this, {
3459 Internal.prototype = redefineAll$2(PromiseConstructorPrototype, {
3460 // `Promise.prototype.then` method
3461 // https://tc39.es/ecma262/#sec-promise.prototype.then
3462 then: function then(onFulfilled, onRejected) {
3463 var state = getInternalPromiseState(this);
3464 var reaction = newPromiseCapability(speciesConstructor$6(this, PromiseConstructor));
3465 reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
3466 reaction.fail = typeof onRejected == 'function' && onRejected;
3467 reaction.domain = IS_NODE$1 ? process$1.domain : undefined;
3468 state.parent = true;
3469 state.reactions.push(reaction);
3470 if (state.state != PENDING) notify(state, false);
3471 return reaction.promise;
3473 // `Promise.prototype.catch` method
3474 // https://tc39.es/ecma262/#sec-promise.prototype.catch
3475 'catch': function (onRejected) {
3476 return this.then(undefined, onRejected);
3479 OwnPromiseCapability = function () {
3480 var promise = new Internal();
3481 var state = getInternalState$2(promise);
3482 this.promise = promise;
3483 this.resolve = bind$8(internalResolve, state);
3484 this.reject = bind$8(internalReject, state);
3486 newPromiseCapabilityModule.f = newPromiseCapability = function (C) {
3487 return C === PromiseConstructor || C === PromiseWrapper
3488 ? new OwnPromiseCapability(C)
3489 : newGenericPromiseCapability(C);
3492 if (typeof NativePromise$1 == 'function' && NativePromisePrototype !== Object.prototype) {
3493 nativeThen = NativePromisePrototype.then;
3496 // make `Promise#then` return a polyfilled `Promise` for native promise-based APIs
3497 redefine$8(NativePromisePrototype, 'then', function then(onFulfilled, onRejected) {
3499 return new PromiseConstructor(function (resolve, reject) {
3500 nativeThen.call(that, resolve, reject);
3501 }).then(onFulfilled, onRejected);
3502 // https://github.com/zloirock/core-js/issues/640
3503 }, { unsafe: true });
3505 // makes sure that native promise-based APIs `Promise#catch` properly works with patched `Promise#then`
3506 redefine$8(NativePromisePrototype, 'catch', PromiseConstructorPrototype['catch'], { unsafe: true });
3509 // make `.constructor === Promise` work for native promise-based APIs
3511 delete NativePromisePrototype.constructor;
3512 } catch (error) { /* empty */ }
3514 // make `instanceof Promise` work for native promise-based APIs
3515 if (setPrototypeOf$3) {
3516 setPrototypeOf$3(NativePromisePrototype, PromiseConstructorPrototype);
3521 $$V({ global: true, wrap: true, forced: FORCED$f }, {
3522 Promise: PromiseConstructor
3525 setToStringTag$5(PromiseConstructor, PROMISE, false);
3526 setSpecies$3(PROMISE);
3528 PromiseWrapper = getBuiltIn$3(PROMISE);
3531 $$V({ target: PROMISE, stat: true, forced: FORCED$f }, {
3532 // `Promise.reject` method
3533 // https://tc39.es/ecma262/#sec-promise.reject
3534 reject: function reject(r) {
3535 var capability = newPromiseCapability(this);
3536 capability.reject.call(undefined, r);
3537 return capability.promise;
3541 $$V({ target: PROMISE, stat: true, forced: FORCED$f }, {
3542 // `Promise.resolve` method
3543 // https://tc39.es/ecma262/#sec-promise.resolve
3544 resolve: function resolve(x) {
3545 return promiseResolve$1(this, x);
3549 $$V({ target: PROMISE, stat: true, forced: INCORRECT_ITERATION$1 }, {
3550 // `Promise.all` method
3551 // https://tc39.es/ecma262/#sec-promise.all
3552 all: function all(iterable) {
3554 var capability = newPromiseCapability(C);
3555 var resolve = capability.resolve;
3556 var reject = capability.reject;
3557 var result = perform(function () {
3558 var $promiseResolve = aFunction$5(C.resolve);
3562 iterate$2(iterable, function (promise) {
3563 var index = counter++;
3564 var alreadyCalled = false;
3565 values.push(undefined);
3567 $promiseResolve.call(C, promise).then(function (value) {
3568 if (alreadyCalled) return;
3569 alreadyCalled = true;
3570 values[index] = value;
3571 --remaining || resolve(values);
3574 --remaining || resolve(values);
3576 if (result.error) reject(result.value);
3577 return capability.promise;
3579 // `Promise.race` method
3580 // https://tc39.es/ecma262/#sec-promise.race
3581 race: function race(iterable) {
3583 var capability = newPromiseCapability(C);
3584 var reject = capability.reject;
3585 var result = perform(function () {
3586 var $promiseResolve = aFunction$5(C.resolve);
3587 iterate$2(iterable, function (promise) {
3588 $promiseResolve.call(C, promise).then(capability.resolve, reject);
3591 if (result.error) reject(result.value);
3592 return capability.promise;
3596 var typedArrayConstructor = {exports: {}};
3598 /* eslint-disable no-new -- required for testing */
3600 var global$g = global$F;
3601 var fails$y = fails$N;
3602 var checkCorrectnessOfIteration$2 = checkCorrectnessOfIteration$4;
3603 var NATIVE_ARRAY_BUFFER_VIEWS$1 = arrayBufferViewCore.NATIVE_ARRAY_BUFFER_VIEWS;
3605 var ArrayBuffer$2 = global$g.ArrayBuffer;
3606 var Int8Array$2 = global$g.Int8Array;
3608 var typedArrayConstructorsRequireWrappers = !NATIVE_ARRAY_BUFFER_VIEWS$1 || !fails$y(function () {
3610 }) || !fails$y(function () {
3611 new Int8Array$2(-1);
3612 }) || !checkCorrectnessOfIteration$2(function (iterable) {
3614 new Int8Array$2(null);
3615 new Int8Array$2(1.5);
3616 new Int8Array$2(iterable);
3617 }, true) || fails$y(function () {
3618 // Safari (11+) bug - a reason why even Safari 13 should load a typed array polyfill
3619 return new Int8Array$2(new ArrayBuffer$2(2), 1, undefined).length !== 1;
3622 var toInteger$5 = toInteger$b;
3624 var toPositiveInteger$1 = function (it) {
3625 var result = toInteger$5(it);
3626 if (result < 0) throw RangeError("The argument can't be less than 0");
3630 var toPositiveInteger = toPositiveInteger$1;
3632 var toOffset$2 = function (it, BYTES) {
3633 var offset = toPositiveInteger(it);
3634 if (offset % BYTES) throw RangeError('Wrong offset');
3638 var toObject$c = toObject$i;
3639 var toLength$i = toLength$q;
3640 var getIteratorMethod$3 = getIteratorMethod$5;
3641 var isArrayIteratorMethod$1 = isArrayIteratorMethod$3;
3642 var bind$7 = functionBindContext;
3643 var aTypedArrayConstructor$4 = arrayBufferViewCore.aTypedArrayConstructor;
3645 var typedArrayFrom$2 = function from(source /* , mapfn, thisArg */) {
3646 var O = toObject$c(source);
3647 var argumentsLength = arguments.length;
3648 var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
3649 var mapping = mapfn !== undefined;
3650 var iteratorMethod = getIteratorMethod$3(O);
3651 var i, length, result, step, iterator, next;
3652 if (iteratorMethod != undefined && !isArrayIteratorMethod$1(iteratorMethod)) {
3653 iterator = iteratorMethod.call(O);
3654 next = iterator.next;
3656 while (!(step = next.call(iterator)).done) {
3660 if (mapping && argumentsLength > 2) {
3661 mapfn = bind$7(mapfn, arguments[2], 2);
3663 length = toLength$i(O.length);
3664 result = new (aTypedArrayConstructor$4(this))(length);
3665 for (i = 0; length > i; i++) {
3666 result[i] = mapping ? mapfn(O[i], i) : O[i];
3671 var isObject$f = isObject$r;
3672 var setPrototypeOf$2 = objectSetPrototypeOf;
3674 // makes subclassing work correct for wrapped built-ins
3675 var inheritIfRequired$4 = function ($this, dummy, Wrapper) {
3676 var NewTarget, NewTargetPrototype;
3678 // it can work only with native `setPrototypeOf`
3680 // we haven't completely correct pre-ES6 way for getting `new.target`, so use this
3681 typeof (NewTarget = dummy.constructor) == 'function' &&
3682 NewTarget !== Wrapper &&
3683 isObject$f(NewTargetPrototype = NewTarget.prototype) &&
3684 NewTargetPrototype !== Wrapper.prototype
3685 ) setPrototypeOf$2($this, NewTargetPrototype);
3690 var global$f = global$F;
3691 var DESCRIPTORS$c = descriptors;
3692 var TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS$1 = typedArrayConstructorsRequireWrappers;
3693 var ArrayBufferViewCore$m = arrayBufferViewCore;
3694 var ArrayBufferModule = arrayBuffer;
3695 var anInstance$4 = anInstance$7;
3696 var createPropertyDescriptor$2 = createPropertyDescriptor$7;
3697 var createNonEnumerableProperty$2 = createNonEnumerableProperty$e;
3698 var toLength$h = toLength$q;
3699 var toIndex = toIndex$2;
3700 var toOffset$1 = toOffset$2;
3701 var toPrimitive$3 = toPrimitive$7;
3703 var classof$5 = classof$b;
3704 var isObject$e = isObject$r;
3705 var create$9 = objectCreate;
3706 var setPrototypeOf$1 = objectSetPrototypeOf;
3707 var getOwnPropertyNames$2 = objectGetOwnPropertyNames.f;
3708 var typedArrayFrom$1 = typedArrayFrom$2;
3709 var forEach$1 = arrayIteration.forEach;
3710 var setSpecies$2 = setSpecies$5;
3711 var definePropertyModule$1 = objectDefineProperty;
3712 var getOwnPropertyDescriptorModule$1 = objectGetOwnPropertyDescriptor;
3713 var InternalStateModule$3 = internalState;
3714 var inheritIfRequired$3 = inheritIfRequired$4;
3716 var getInternalState$1 = InternalStateModule$3.get;
3717 var setInternalState$3 = InternalStateModule$3.set;
3718 var nativeDefineProperty = definePropertyModule$1.f;
3719 var nativeGetOwnPropertyDescriptor$1 = getOwnPropertyDescriptorModule$1.f;
3720 var round = Math.round;
3721 var RangeError$1 = global$f.RangeError;
3722 var ArrayBuffer$1 = ArrayBufferModule.ArrayBuffer;
3723 var DataView$1 = ArrayBufferModule.DataView;
3724 var NATIVE_ARRAY_BUFFER_VIEWS = ArrayBufferViewCore$m.NATIVE_ARRAY_BUFFER_VIEWS;
3725 var TYPED_ARRAY_TAG = ArrayBufferViewCore$m.TYPED_ARRAY_TAG;
3726 var TypedArray = ArrayBufferViewCore$m.TypedArray;
3727 var TypedArrayPrototype = ArrayBufferViewCore$m.TypedArrayPrototype;
3728 var aTypedArrayConstructor$3 = ArrayBufferViewCore$m.aTypedArrayConstructor;
3729 var isTypedArray = ArrayBufferViewCore$m.isTypedArray;
3730 var BYTES_PER_ELEMENT = 'BYTES_PER_ELEMENT';
3731 var WRONG_LENGTH = 'Wrong length';
3733 var fromList = function (C, list) {
3735 var length = list.length;
3736 var result = new (aTypedArrayConstructor$3(C))(length);
3737 while (length > index) result[index] = list[index++];
3741 var addGetter = function (it, key) {
3742 nativeDefineProperty(it, key, { get: function () {
3743 return getInternalState$1(this)[key];
3747 var isArrayBuffer = function (it) {
3749 return it instanceof ArrayBuffer$1 || (klass = classof$5(it)) == 'ArrayBuffer' || klass == 'SharedArrayBuffer';
3752 var isTypedArrayIndex = function (target, key) {
3753 return isTypedArray(target)
3754 && typeof key != 'symbol'
3756 && String(+key) == String(key);
3759 var wrappedGetOwnPropertyDescriptor = function getOwnPropertyDescriptor(target, key) {
3760 return isTypedArrayIndex(target, key = toPrimitive$3(key, true))
3761 ? createPropertyDescriptor$2(2, target[key])
3762 : nativeGetOwnPropertyDescriptor$1(target, key);
3765 var wrappedDefineProperty = function defineProperty(target, key, descriptor) {
3766 if (isTypedArrayIndex(target, key = toPrimitive$3(key, true))
3767 && isObject$e(descriptor)
3768 && has$5(descriptor, 'value')
3769 && !has$5(descriptor, 'get')
3770 && !has$5(descriptor, 'set')
3771 // TODO: add validation descriptor w/o calling accessors
3772 && !descriptor.configurable
3773 && (!has$5(descriptor, 'writable') || descriptor.writable)
3774 && (!has$5(descriptor, 'enumerable') || descriptor.enumerable)
3776 target[key] = descriptor.value;
3778 } return nativeDefineProperty(target, key, descriptor);
3781 if (DESCRIPTORS$c) {
3782 if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3783 getOwnPropertyDescriptorModule$1.f = wrappedGetOwnPropertyDescriptor;
3784 definePropertyModule$1.f = wrappedDefineProperty;
3785 addGetter(TypedArrayPrototype, 'buffer');
3786 addGetter(TypedArrayPrototype, 'byteOffset');
3787 addGetter(TypedArrayPrototype, 'byteLength');
3788 addGetter(TypedArrayPrototype, 'length');
3791 $$U({ target: 'Object', stat: true, forced: !NATIVE_ARRAY_BUFFER_VIEWS }, {
3792 getOwnPropertyDescriptor: wrappedGetOwnPropertyDescriptor,
3793 defineProperty: wrappedDefineProperty
3796 typedArrayConstructor.exports = function (TYPE, wrapper, CLAMPED) {
3797 var BYTES = TYPE.match(/\d+$/)[0] / 8;
3798 var CONSTRUCTOR_NAME = TYPE + (CLAMPED ? 'Clamped' : '') + 'Array';
3799 var GETTER = 'get' + TYPE;
3800 var SETTER = 'set' + TYPE;
3801 var NativeTypedArrayConstructor = global$f[CONSTRUCTOR_NAME];
3802 var TypedArrayConstructor = NativeTypedArrayConstructor;
3803 var TypedArrayConstructorPrototype = TypedArrayConstructor && TypedArrayConstructor.prototype;
3806 var getter = function (that, index) {
3807 var data = getInternalState$1(that);
3808 return data.view[GETTER](index * BYTES + data.byteOffset, true);
3811 var setter = function (that, index, value) {
3812 var data = getInternalState$1(that);
3813 if (CLAMPED) value = (value = round(value)) < 0 ? 0 : value > 0xFF ? 0xFF : value & 0xFF;
3814 data.view[SETTER](index * BYTES + data.byteOffset, value, true);
3817 var addElement = function (that, index) {
3818 nativeDefineProperty(that, index, {
3820 return getter(this, index);
3822 set: function (value) {
3823 return setter(this, index, value);
3829 if (!NATIVE_ARRAY_BUFFER_VIEWS) {
3830 TypedArrayConstructor = wrapper(function (that, data, offset, $length) {
3831 anInstance$4(that, TypedArrayConstructor, CONSTRUCTOR_NAME);
3834 var buffer, byteLength, length;
3835 if (!isObject$e(data)) {
3836 length = toIndex(data);
3837 byteLength = length * BYTES;
3838 buffer = new ArrayBuffer$1(byteLength);
3839 } else if (isArrayBuffer(data)) {
3841 byteOffset = toOffset$1(offset, BYTES);
3842 var $len = data.byteLength;
3843 if ($length === undefined) {
3844 if ($len % BYTES) throw RangeError$1(WRONG_LENGTH);
3845 byteLength = $len - byteOffset;
3846 if (byteLength < 0) throw RangeError$1(WRONG_LENGTH);
3848 byteLength = toLength$h($length) * BYTES;
3849 if (byteLength + byteOffset > $len) throw RangeError$1(WRONG_LENGTH);
3851 length = byteLength / BYTES;
3852 } else if (isTypedArray(data)) {
3853 return fromList(TypedArrayConstructor, data);
3855 return typedArrayFrom$1.call(TypedArrayConstructor, data);
3857 setInternalState$3(that, {
3859 byteOffset: byteOffset,
3860 byteLength: byteLength,
3862 view: new DataView$1(buffer)
3864 while (index < length) addElement(that, index++);
3867 if (setPrototypeOf$1) setPrototypeOf$1(TypedArrayConstructor, TypedArray);
3868 TypedArrayConstructorPrototype = TypedArrayConstructor.prototype = create$9(TypedArrayPrototype);
3869 } else if (TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS$1) {
3870 TypedArrayConstructor = wrapper(function (dummy, data, typedArrayOffset, $length) {
3871 anInstance$4(dummy, TypedArrayConstructor, CONSTRUCTOR_NAME);
3872 return inheritIfRequired$3(function () {
3873 if (!isObject$e(data)) return new NativeTypedArrayConstructor(toIndex(data));
3874 if (isArrayBuffer(data)) return $length !== undefined
3875 ? new NativeTypedArrayConstructor(data, toOffset$1(typedArrayOffset, BYTES), $length)
3876 : typedArrayOffset !== undefined
3877 ? new NativeTypedArrayConstructor(data, toOffset$1(typedArrayOffset, BYTES))
3878 : new NativeTypedArrayConstructor(data);
3879 if (isTypedArray(data)) return fromList(TypedArrayConstructor, data);
3880 return typedArrayFrom$1.call(TypedArrayConstructor, data);
3881 }(), dummy, TypedArrayConstructor);
3884 if (setPrototypeOf$1) setPrototypeOf$1(TypedArrayConstructor, TypedArray);
3885 forEach$1(getOwnPropertyNames$2(NativeTypedArrayConstructor), function (key) {
3886 if (!(key in TypedArrayConstructor)) {
3887 createNonEnumerableProperty$2(TypedArrayConstructor, key, NativeTypedArrayConstructor[key]);
3890 TypedArrayConstructor.prototype = TypedArrayConstructorPrototype;
3893 if (TypedArrayConstructorPrototype.constructor !== TypedArrayConstructor) {
3894 createNonEnumerableProperty$2(TypedArrayConstructorPrototype, 'constructor', TypedArrayConstructor);
3897 if (TYPED_ARRAY_TAG) {
3898 createNonEnumerableProperty$2(TypedArrayConstructorPrototype, TYPED_ARRAY_TAG, CONSTRUCTOR_NAME);
3901 exported[CONSTRUCTOR_NAME] = TypedArrayConstructor;
3904 global: true, forced: TypedArrayConstructor != NativeTypedArrayConstructor, sham: !NATIVE_ARRAY_BUFFER_VIEWS
3907 if (!(BYTES_PER_ELEMENT in TypedArrayConstructor)) {
3908 createNonEnumerableProperty$2(TypedArrayConstructor, BYTES_PER_ELEMENT, BYTES);
3911 if (!(BYTES_PER_ELEMENT in TypedArrayConstructorPrototype)) {
3912 createNonEnumerableProperty$2(TypedArrayConstructorPrototype, BYTES_PER_ELEMENT, BYTES);
3915 setSpecies$2(CONSTRUCTOR_NAME);
3917 } else typedArrayConstructor.exports = function () { /* empty */ };
3919 var createTypedArrayConstructor$1 = typedArrayConstructor.exports;
3921 // `Uint8Array` constructor
3922 // https://tc39.es/ecma262/#sec-typedarray-objects
3923 createTypedArrayConstructor$1('Uint8', function (init) {
3924 return function Uint8Array(data, byteOffset, length) {
3925 return init(this, data, byteOffset, length);
3929 var toObject$b = toObject$i;
3930 var toAbsoluteIndex$4 = toAbsoluteIndex$8;
3931 var toLength$g = toLength$q;
3933 var min$7 = Math.min;
3935 // `Array.prototype.copyWithin` method implementation
3936 // https://tc39.es/ecma262/#sec-array.prototype.copywithin
3937 // eslint-disable-next-line es/no-array-prototype-copywithin -- safe
3938 var arrayCopyWithin = [].copyWithin || function copyWithin(target /* = 0 */, start /* = 0, end = @length */) {
3939 var O = toObject$b(this);
3940 var len = toLength$g(O.length);
3941 var to = toAbsoluteIndex$4(target, len);
3942 var from = toAbsoluteIndex$4(start, len);
3943 var end = arguments.length > 2 ? arguments[2] : undefined;
3944 var count = min$7((end === undefined ? len : toAbsoluteIndex$4(end, len)) - from, len - to);
3946 if (from < to && to < from + count) {
3951 while (count-- > 0) {
3952 if (from in O) O[to] = O[from];
3959 var ArrayBufferViewCore$l = arrayBufferViewCore;
3960 var $copyWithin = arrayCopyWithin;
3962 var aTypedArray$l = ArrayBufferViewCore$l.aTypedArray;
3963 var exportTypedArrayMethod$m = ArrayBufferViewCore$l.exportTypedArrayMethod;
3965 // `%TypedArray%.prototype.copyWithin` method
3966 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.copywithin
3967 exportTypedArrayMethod$m('copyWithin', function copyWithin(target, start /* , end */) {
3968 return $copyWithin.call(aTypedArray$l(this), target, start, arguments.length > 2 ? arguments[2] : undefined);
3971 var ArrayBufferViewCore$k = arrayBufferViewCore;
3972 var $every$1 = arrayIteration.every;
3974 var aTypedArray$k = ArrayBufferViewCore$k.aTypedArray;
3975 var exportTypedArrayMethod$l = ArrayBufferViewCore$k.exportTypedArrayMethod;
3977 // `%TypedArray%.prototype.every` method
3978 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.every
3979 exportTypedArrayMethod$l('every', function every(callbackfn /* , thisArg */) {
3980 return $every$1(aTypedArray$k(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
3983 var ArrayBufferViewCore$j = arrayBufferViewCore;
3984 var $fill = arrayFill$1;
3986 var aTypedArray$j = ArrayBufferViewCore$j.aTypedArray;
3987 var exportTypedArrayMethod$k = ArrayBufferViewCore$j.exportTypedArrayMethod;
3989 // `%TypedArray%.prototype.fill` method
3990 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.fill
3991 // eslint-disable-next-line no-unused-vars -- required for `.length`
3992 exportTypedArrayMethod$k('fill', function fill(value /* , start, end */) {
3993 return $fill.apply(aTypedArray$j(this), arguments);
3996 var aTypedArrayConstructor$2 = arrayBufferViewCore.aTypedArrayConstructor;
3997 var speciesConstructor$5 = speciesConstructor$8;
3999 var typedArrayFromSpeciesAndList = function (instance, list) {
4000 var C = speciesConstructor$5(instance, instance.constructor);
4002 var length = list.length;
4003 var result = new (aTypedArrayConstructor$2(C))(length);
4004 while (length > index) result[index] = list[index++];
4008 var ArrayBufferViewCore$i = arrayBufferViewCore;
4009 var $filter$1 = arrayIteration.filter;
4010 var fromSpeciesAndList = typedArrayFromSpeciesAndList;
4012 var aTypedArray$i = ArrayBufferViewCore$i.aTypedArray;
4013 var exportTypedArrayMethod$j = ArrayBufferViewCore$i.exportTypedArrayMethod;
4015 // `%TypedArray%.prototype.filter` method
4016 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.filter
4017 exportTypedArrayMethod$j('filter', function filter(callbackfn /* , thisArg */) {
4018 var list = $filter$1(aTypedArray$i(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4019 return fromSpeciesAndList(this, list);
4022 var ArrayBufferViewCore$h = arrayBufferViewCore;
4023 var $find$1 = arrayIteration.find;
4025 var aTypedArray$h = ArrayBufferViewCore$h.aTypedArray;
4026 var exportTypedArrayMethod$i = ArrayBufferViewCore$h.exportTypedArrayMethod;
4028 // `%TypedArray%.prototype.find` method
4029 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.find
4030 exportTypedArrayMethod$i('find', function find(predicate /* , thisArg */) {
4031 return $find$1(aTypedArray$h(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4034 var ArrayBufferViewCore$g = arrayBufferViewCore;
4035 var $findIndex$1 = arrayIteration.findIndex;
4037 var aTypedArray$g = ArrayBufferViewCore$g.aTypedArray;
4038 var exportTypedArrayMethod$h = ArrayBufferViewCore$g.exportTypedArrayMethod;
4040 // `%TypedArray%.prototype.findIndex` method
4041 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.findindex
4042 exportTypedArrayMethod$h('findIndex', function findIndex(predicate /* , thisArg */) {
4043 return $findIndex$1(aTypedArray$g(this), predicate, arguments.length > 1 ? arguments[1] : undefined);
4046 var ArrayBufferViewCore$f = arrayBufferViewCore;
4047 var $forEach = arrayIteration.forEach;
4049 var aTypedArray$f = ArrayBufferViewCore$f.aTypedArray;
4050 var exportTypedArrayMethod$g = ArrayBufferViewCore$f.exportTypedArrayMethod;
4052 // `%TypedArray%.prototype.forEach` method
4053 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.foreach
4054 exportTypedArrayMethod$g('forEach', function forEach(callbackfn /* , thisArg */) {
4055 $forEach(aTypedArray$f(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4058 var ArrayBufferViewCore$e = arrayBufferViewCore;
4059 var $includes$1 = arrayIncludes.includes;
4061 var aTypedArray$e = ArrayBufferViewCore$e.aTypedArray;
4062 var exportTypedArrayMethod$f = ArrayBufferViewCore$e.exportTypedArrayMethod;
4064 // `%TypedArray%.prototype.includes` method
4065 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.includes
4066 exportTypedArrayMethod$f('includes', function includes(searchElement /* , fromIndex */) {
4067 return $includes$1(aTypedArray$e(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4070 var ArrayBufferViewCore$d = arrayBufferViewCore;
4071 var $indexOf = arrayIncludes.indexOf;
4073 var aTypedArray$d = ArrayBufferViewCore$d.aTypedArray;
4074 var exportTypedArrayMethod$e = ArrayBufferViewCore$d.exportTypedArrayMethod;
4076 // `%TypedArray%.prototype.indexOf` method
4077 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.indexof
4078 exportTypedArrayMethod$e('indexOf', function indexOf(searchElement /* , fromIndex */) {
4079 return $indexOf(aTypedArray$d(this), searchElement, arguments.length > 1 ? arguments[1] : undefined);
4082 var global$e = global$F;
4083 var ArrayBufferViewCore$c = arrayBufferViewCore;
4084 var ArrayIterators = es_array_iterator;
4085 var wellKnownSymbol$9 = wellKnownSymbol$s;
4087 var ITERATOR$2 = wellKnownSymbol$9('iterator');
4088 var Uint8Array$2 = global$e.Uint8Array;
4089 var arrayValues = ArrayIterators.values;
4090 var arrayKeys = ArrayIterators.keys;
4091 var arrayEntries = ArrayIterators.entries;
4092 var aTypedArray$c = ArrayBufferViewCore$c.aTypedArray;
4093 var exportTypedArrayMethod$d = ArrayBufferViewCore$c.exportTypedArrayMethod;
4094 var nativeTypedArrayIterator = Uint8Array$2 && Uint8Array$2.prototype[ITERATOR$2];
4096 var CORRECT_ITER_NAME = !!nativeTypedArrayIterator
4097 && (nativeTypedArrayIterator.name == 'values' || nativeTypedArrayIterator.name == undefined);
4099 var typedArrayValues = function values() {
4100 return arrayValues.call(aTypedArray$c(this));
4103 // `%TypedArray%.prototype.entries` method
4104 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.entries
4105 exportTypedArrayMethod$d('entries', function entries() {
4106 return arrayEntries.call(aTypedArray$c(this));
4108 // `%TypedArray%.prototype.keys` method
4109 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.keys
4110 exportTypedArrayMethod$d('keys', function keys() {
4111 return arrayKeys.call(aTypedArray$c(this));
4113 // `%TypedArray%.prototype.values` method
4114 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.values
4115 exportTypedArrayMethod$d('values', typedArrayValues, !CORRECT_ITER_NAME);
4116 // `%TypedArray%.prototype[@@iterator]` method
4117 // https://tc39.es/ecma262/#sec-%typedarray%.prototype-@@iterator
4118 exportTypedArrayMethod$d(ITERATOR$2, typedArrayValues, !CORRECT_ITER_NAME);
4120 var ArrayBufferViewCore$b = arrayBufferViewCore;
4122 var aTypedArray$b = ArrayBufferViewCore$b.aTypedArray;
4123 var exportTypedArrayMethod$c = ArrayBufferViewCore$b.exportTypedArrayMethod;
4124 var $join = [].join;
4126 // `%TypedArray%.prototype.join` method
4127 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.join
4128 // eslint-disable-next-line no-unused-vars -- required for `.length`
4129 exportTypedArrayMethod$c('join', function join(separator) {
4130 return $join.apply(aTypedArray$b(this), arguments);
4133 /* eslint-disable es/no-array-prototype-lastindexof -- safe */
4134 var toIndexedObject$4 = toIndexedObject$b;
4135 var toInteger$4 = toInteger$b;
4136 var toLength$f = toLength$q;
4137 var arrayMethodIsStrict$5 = arrayMethodIsStrict$8;
4139 var min$6 = Math.min;
4140 var $lastIndexOf$1 = [].lastIndexOf;
4141 var NEGATIVE_ZERO = !!$lastIndexOf$1 && 1 / [1].lastIndexOf(1, -0) < 0;
4142 var STRICT_METHOD$5 = arrayMethodIsStrict$5('lastIndexOf');
4143 var FORCED$e = NEGATIVE_ZERO || !STRICT_METHOD$5;
4145 // `Array.prototype.lastIndexOf` method implementation
4146 // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
4147 var arrayLastIndexOf = FORCED$e ? function lastIndexOf(searchElement /* , fromIndex = @[*-1] */) {
4149 if (NEGATIVE_ZERO) return $lastIndexOf$1.apply(this, arguments) || 0;
4150 var O = toIndexedObject$4(this);
4151 var length = toLength$f(O.length);
4152 var index = length - 1;
4153 if (arguments.length > 1) index = min$6(index, toInteger$4(arguments[1]));
4154 if (index < 0) index = length + index;
4155 for (;index >= 0; index--) if (index in O && O[index] === searchElement) return index || 0;
4159 var ArrayBufferViewCore$a = arrayBufferViewCore;
4160 var $lastIndexOf = arrayLastIndexOf;
4162 var aTypedArray$a = ArrayBufferViewCore$a.aTypedArray;
4163 var exportTypedArrayMethod$b = ArrayBufferViewCore$a.exportTypedArrayMethod;
4165 // `%TypedArray%.prototype.lastIndexOf` method
4166 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.lastindexof
4167 // eslint-disable-next-line no-unused-vars -- required for `.length`
4168 exportTypedArrayMethod$b('lastIndexOf', function lastIndexOf(searchElement /* , fromIndex */) {
4169 return $lastIndexOf.apply(aTypedArray$a(this), arguments);
4172 var ArrayBufferViewCore$9 = arrayBufferViewCore;
4173 var $map = arrayIteration.map;
4174 var speciesConstructor$4 = speciesConstructor$8;
4176 var aTypedArray$9 = ArrayBufferViewCore$9.aTypedArray;
4177 var aTypedArrayConstructor$1 = ArrayBufferViewCore$9.aTypedArrayConstructor;
4178 var exportTypedArrayMethod$a = ArrayBufferViewCore$9.exportTypedArrayMethod;
4180 // `%TypedArray%.prototype.map` method
4181 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.map
4182 exportTypedArrayMethod$a('map', function map(mapfn /* , thisArg */) {
4183 return $map(aTypedArray$9(this), mapfn, arguments.length > 1 ? arguments[1] : undefined, function (O, length) {
4184 return new (aTypedArrayConstructor$1(speciesConstructor$4(O, O.constructor)))(length);
4188 var aFunction$4 = aFunction$9;
4189 var toObject$a = toObject$i;
4190 var IndexedObject$2 = indexedObject;
4191 var toLength$e = toLength$q;
4193 // `Array.prototype.{ reduce, reduceRight }` methods implementation
4194 var createMethod$3 = function (IS_RIGHT) {
4195 return function (that, callbackfn, argumentsLength, memo) {
4196 aFunction$4(callbackfn);
4197 var O = toObject$a(that);
4198 var self = IndexedObject$2(O);
4199 var length = toLength$e(O.length);
4200 var index = IS_RIGHT ? length - 1 : 0;
4201 var i = IS_RIGHT ? -1 : 1;
4202 if (argumentsLength < 2) while (true) {
4203 if (index in self) {
4209 if (IS_RIGHT ? index < 0 : length <= index) {
4210 throw TypeError('Reduce of empty array with no initial value');
4213 for (;IS_RIGHT ? index >= 0 : length > index; index += i) if (index in self) {
4214 memo = callbackfn(memo, self[index], index, O);
4221 // `Array.prototype.reduce` method
4222 // https://tc39.es/ecma262/#sec-array.prototype.reduce
4223 left: createMethod$3(false),
4224 // `Array.prototype.reduceRight` method
4225 // https://tc39.es/ecma262/#sec-array.prototype.reduceright
4226 right: createMethod$3(true)
4229 var ArrayBufferViewCore$8 = arrayBufferViewCore;
4230 var $reduce$1 = arrayReduce.left;
4232 var aTypedArray$8 = ArrayBufferViewCore$8.aTypedArray;
4233 var exportTypedArrayMethod$9 = ArrayBufferViewCore$8.exportTypedArrayMethod;
4235 // `%TypedArray%.prototype.reduce` method
4236 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduce
4237 exportTypedArrayMethod$9('reduce', function reduce(callbackfn /* , initialValue */) {
4238 return $reduce$1(aTypedArray$8(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4241 var ArrayBufferViewCore$7 = arrayBufferViewCore;
4242 var $reduceRight = arrayReduce.right;
4244 var aTypedArray$7 = ArrayBufferViewCore$7.aTypedArray;
4245 var exportTypedArrayMethod$8 = ArrayBufferViewCore$7.exportTypedArrayMethod;
4247 // `%TypedArray%.prototype.reduceRicht` method
4248 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reduceright
4249 exportTypedArrayMethod$8('reduceRight', function reduceRight(callbackfn /* , initialValue */) {
4250 return $reduceRight(aTypedArray$7(this), callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
4253 var ArrayBufferViewCore$6 = arrayBufferViewCore;
4255 var aTypedArray$6 = ArrayBufferViewCore$6.aTypedArray;
4256 var exportTypedArrayMethod$7 = ArrayBufferViewCore$6.exportTypedArrayMethod;
4257 var floor$5 = Math.floor;
4259 // `%TypedArray%.prototype.reverse` method
4260 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.reverse
4261 exportTypedArrayMethod$7('reverse', function reverse() {
4263 var length = aTypedArray$6(that).length;
4264 var middle = floor$5(length / 2);
4267 while (index < middle) {
4268 value = that[index];
4269 that[index++] = that[--length];
4270 that[length] = value;
4274 var ArrayBufferViewCore$5 = arrayBufferViewCore;
4275 var toLength$d = toLength$q;
4276 var toOffset = toOffset$2;
4277 var toObject$9 = toObject$i;
4278 var fails$x = fails$N;
4280 var aTypedArray$5 = ArrayBufferViewCore$5.aTypedArray;
4281 var exportTypedArrayMethod$6 = ArrayBufferViewCore$5.exportTypedArrayMethod;
4283 var FORCED$d = fails$x(function () {
4284 // eslint-disable-next-line es/no-typed-arrays -- required for testing
4285 new Int8Array(1).set({});
4288 // `%TypedArray%.prototype.set` method
4289 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.set
4290 exportTypedArrayMethod$6('set', function set(arrayLike /* , offset */) {
4291 aTypedArray$5(this);
4292 var offset = toOffset(arguments.length > 1 ? arguments[1] : undefined, 1);
4293 var length = this.length;
4294 var src = toObject$9(arrayLike);
4295 var len = toLength$d(src.length);
4297 if (len + offset > length) throw RangeError('Wrong length');
4298 while (index < len) this[offset + index] = src[index++];
4301 var ArrayBufferViewCore$4 = arrayBufferViewCore;
4302 var speciesConstructor$3 = speciesConstructor$8;
4303 var fails$w = fails$N;
4305 var aTypedArray$4 = ArrayBufferViewCore$4.aTypedArray;
4306 var aTypedArrayConstructor = ArrayBufferViewCore$4.aTypedArrayConstructor;
4307 var exportTypedArrayMethod$5 = ArrayBufferViewCore$4.exportTypedArrayMethod;
4308 var $slice$1 = [].slice;
4310 var FORCED$c = fails$w(function () {
4311 // eslint-disable-next-line es/no-typed-arrays -- required for testing
4312 new Int8Array(1).slice();
4315 // `%TypedArray%.prototype.slice` method
4316 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
4317 exportTypedArrayMethod$5('slice', function slice(start, end) {
4318 var list = $slice$1.call(aTypedArray$4(this), start, end);
4319 var C = speciesConstructor$3(this, this.constructor);
4321 var length = list.length;
4322 var result = new (aTypedArrayConstructor(C))(length);
4323 while (length > index) result[index] = list[index++];
4327 var ArrayBufferViewCore$3 = arrayBufferViewCore;
4328 var $some$1 = arrayIteration.some;
4330 var aTypedArray$3 = ArrayBufferViewCore$3.aTypedArray;
4331 var exportTypedArrayMethod$4 = ArrayBufferViewCore$3.exportTypedArrayMethod;
4333 // `%TypedArray%.prototype.some` method
4334 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.some
4335 exportTypedArrayMethod$4('some', function some(callbackfn /* , thisArg */) {
4336 return $some$1(aTypedArray$3(this), callbackfn, arguments.length > 1 ? arguments[1] : undefined);
4339 // TODO: use something more complex like timsort?
4340 var floor$4 = Math.floor;
4342 var mergeSort = function (array, comparefn) {
4343 var length = array.length;
4344 var middle = floor$4(length / 2);
4345 return length < 8 ? insertionSort(array, comparefn) : merge$5(
4346 mergeSort(array.slice(0, middle), comparefn),
4347 mergeSort(array.slice(middle), comparefn),
4352 var insertionSort = function (array, comparefn) {
4353 var length = array.length;
4357 while (i < length) {
4360 while (j && comparefn(array[j - 1], element) > 0) {
4361 array[j] = array[--j];
4363 if (j !== i++) array[j] = element;
4367 var merge$5 = function (left, right, comparefn) {
4368 var llength = left.length;
4369 var rlength = right.length;
4374 while (lindex < llength || rindex < rlength) {
4375 if (lindex < llength && rindex < rlength) {
4376 result.push(comparefn(left[lindex], right[rindex]) <= 0 ? left[lindex++] : right[rindex++]);
4378 result.push(lindex < llength ? left[lindex++] : right[rindex++]);
4383 var arraySort = mergeSort;
4385 var userAgent$2 = engineUserAgent;
4387 var firefox = userAgent$2.match(/firefox\/(\d+)/i);
4389 var engineFfVersion = !!firefox && +firefox[1];
4391 var UA = engineUserAgent;
4393 var engineIsIeOrEdge = /MSIE|Trident/.test(UA);
4395 var userAgent$1 = engineUserAgent;
4397 var webkit = userAgent$1.match(/AppleWebKit\/(\d+)\./);
4399 var engineWebkitVersion = !!webkit && +webkit[1];
4401 var ArrayBufferViewCore$2 = arrayBufferViewCore;
4402 var global$d = global$F;
4403 var fails$v = fails$N;
4404 var aFunction$3 = aFunction$9;
4405 var toLength$c = toLength$q;
4406 var internalSort$1 = arraySort;
4407 var FF$1 = engineFfVersion;
4408 var IE_OR_EDGE$1 = engineIsIeOrEdge;
4409 var V8$1 = engineV8Version;
4410 var WEBKIT$1 = engineWebkitVersion;
4412 var aTypedArray$2 = ArrayBufferViewCore$2.aTypedArray;
4413 var exportTypedArrayMethod$3 = ArrayBufferViewCore$2.exportTypedArrayMethod;
4414 var Uint16Array = global$d.Uint16Array;
4415 var nativeSort$1 = Uint16Array && Uint16Array.prototype.sort;
4418 var ACCEPT_INCORRECT_ARGUMENTS = !!nativeSort$1 && !fails$v(function () {
4419 var array = new Uint16Array(2);
4424 var STABLE_SORT$1 = !!nativeSort$1 && !fails$v(function () {
4425 // feature detection can be too slow, so check engines versions
4426 if (V8$1) return V8$1 < 74;
4427 if (FF$1) return FF$1 < 67;
4428 if (IE_OR_EDGE$1) return true;
4429 if (WEBKIT$1) return WEBKIT$1 < 602;
4431 var array = new Uint16Array(516);
4432 var expected = Array(516);
4435 for (index = 0; index < 516; index++) {
4437 array[index] = 515 - index;
4438 expected[index] = index - 2 * mod + 3;
4441 array.sort(function (a, b) {
4442 return (a / 4 | 0) - (b / 4 | 0);
4445 for (index = 0; index < 516; index++) {
4446 if (array[index] !== expected[index]) return true;
4450 var getSortCompare$1 = function (comparefn) {
4451 return function (x, y) {
4452 if (comparefn !== undefined) return +comparefn(x, y) || 0;
4453 // eslint-disable-next-line no-self-compare -- NaN check
4454 if (y !== y) return -1;
4455 // eslint-disable-next-line no-self-compare -- NaN check
4456 if (x !== x) return 1;
4457 if (x === 0 && y === 0) return 1 / x > 0 && 1 / y < 0 ? 1 : -1;
4462 // `%TypedArray%.prototype.sort` method
4463 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.sort
4464 exportTypedArrayMethod$3('sort', function sort(comparefn) {
4466 if (comparefn !== undefined) aFunction$3(comparefn);
4467 if (STABLE_SORT$1) return nativeSort$1.call(array, comparefn);
4469 aTypedArray$2(array);
4470 var arrayLength = toLength$c(array.length);
4471 var items = Array(arrayLength);
4474 for (index = 0; index < arrayLength; index++) {
4475 items[index] = array[index];
4478 items = internalSort$1(array, getSortCompare$1(comparefn));
4480 for (index = 0; index < arrayLength; index++) {
4481 array[index] = items[index];
4485 }, !STABLE_SORT$1 || ACCEPT_INCORRECT_ARGUMENTS);
4487 var ArrayBufferViewCore$1 = arrayBufferViewCore;
4488 var toLength$b = toLength$q;
4489 var toAbsoluteIndex$3 = toAbsoluteIndex$8;
4490 var speciesConstructor$2 = speciesConstructor$8;
4492 var aTypedArray$1 = ArrayBufferViewCore$1.aTypedArray;
4493 var exportTypedArrayMethod$2 = ArrayBufferViewCore$1.exportTypedArrayMethod;
4495 // `%TypedArray%.prototype.subarray` method
4496 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.subarray
4497 exportTypedArrayMethod$2('subarray', function subarray(begin, end) {
4498 var O = aTypedArray$1(this);
4499 var length = O.length;
4500 var beginIndex = toAbsoluteIndex$3(begin, length);
4501 return new (speciesConstructor$2(O, O.constructor))(
4503 O.byteOffset + beginIndex * O.BYTES_PER_ELEMENT,
4504 toLength$b((end === undefined ? length : toAbsoluteIndex$3(end, length)) - beginIndex)
4508 var global$c = global$F;
4509 var ArrayBufferViewCore = arrayBufferViewCore;
4510 var fails$u = fails$N;
4512 var Int8Array$1 = global$c.Int8Array;
4513 var aTypedArray = ArrayBufferViewCore.aTypedArray;
4514 var exportTypedArrayMethod$1 = ArrayBufferViewCore.exportTypedArrayMethod;
4515 var $toLocaleString = [].toLocaleString;
4516 var $slice = [].slice;
4518 // iOS Safari 6.x fails here
4519 var TO_LOCALE_STRING_BUG = !!Int8Array$1 && fails$u(function () {
4520 $toLocaleString.call(new Int8Array$1(1));
4523 var FORCED$b = fails$u(function () {
4524 return [1, 2].toLocaleString() != new Int8Array$1([1, 2]).toLocaleString();
4525 }) || !fails$u(function () {
4526 Int8Array$1.prototype.toLocaleString.call([1, 2]);
4529 // `%TypedArray%.prototype.toLocaleString` method
4530 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tolocalestring
4531 exportTypedArrayMethod$1('toLocaleString', function toLocaleString() {
4532 return $toLocaleString.apply(TO_LOCALE_STRING_BUG ? $slice.call(aTypedArray(this)) : aTypedArray(this), arguments);
4535 var exportTypedArrayMethod = arrayBufferViewCore.exportTypedArrayMethod;
4536 var fails$t = fails$N;
4537 var global$b = global$F;
4539 var Uint8Array$1 = global$b.Uint8Array;
4540 var Uint8ArrayPrototype = Uint8Array$1 && Uint8Array$1.prototype || {};
4541 var arrayToString = [].toString;
4542 var arrayJoin = [].join;
4544 if (fails$t(function () { arrayToString.call({}); })) {
4545 arrayToString = function toString() {
4546 return arrayJoin.call(this);
4550 var IS_NOT_ARRAY_METHOD = Uint8ArrayPrototype.toString != arrayToString;
4552 // `%TypedArray%.prototype.toString` method
4553 // https://tc39.es/ecma262/#sec-%typedarray%.prototype.tostring
4554 exportTypedArrayMethod('toString', arrayToString, IS_NOT_ARRAY_METHOD);
4557 var IndexedObject$1 = indexedObject;
4558 var toIndexedObject$3 = toIndexedObject$b;
4559 var arrayMethodIsStrict$4 = arrayMethodIsStrict$8;
4561 var nativeJoin = [].join;
4563 var ES3_STRINGS = IndexedObject$1 != Object;
4564 var STRICT_METHOD$4 = arrayMethodIsStrict$4('join', ',');
4566 // `Array.prototype.join` method
4567 // https://tc39.es/ecma262/#sec-array.prototype.join
4568 $$T({ target: 'Array', proto: true, forced: ES3_STRINGS || !STRICT_METHOD$4 }, {
4569 join: function join(separator) {
4570 return nativeJoin.call(toIndexedObject$3(this), separator === undefined ? ',' : separator);
4574 var toPrimitive$2 = toPrimitive$7;
4575 var definePropertyModule = objectDefineProperty;
4576 var createPropertyDescriptor$1 = createPropertyDescriptor$7;
4578 var createProperty$4 = function (object, key, value) {
4579 var propertyKey = toPrimitive$2(key);
4580 if (propertyKey in object) definePropertyModule.f(object, propertyKey, createPropertyDescriptor$1(0, value));
4581 else object[propertyKey] = value;
4585 var isObject$d = isObject$r;
4586 var isArray$2 = isArray$6;
4587 var toAbsoluteIndex$2 = toAbsoluteIndex$8;
4588 var toLength$a = toLength$q;
4589 var toIndexedObject$2 = toIndexedObject$b;
4590 var createProperty$3 = createProperty$4;
4591 var wellKnownSymbol$8 = wellKnownSymbol$s;
4592 var arrayMethodHasSpeciesSupport$3 = arrayMethodHasSpeciesSupport$5;
4594 var HAS_SPECIES_SUPPORT$2 = arrayMethodHasSpeciesSupport$3('slice');
4596 var SPECIES$1 = wellKnownSymbol$8('species');
4597 var nativeSlice = [].slice;
4598 var max$3 = Math.max;
4600 // `Array.prototype.slice` method
4601 // https://tc39.es/ecma262/#sec-array.prototype.slice
4602 // fallback for not array-like ES3 strings and DOM objects
4603 $$S({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$2 }, {
4604 slice: function slice(start, end) {
4605 var O = toIndexedObject$2(this);
4606 var length = toLength$a(O.length);
4607 var k = toAbsoluteIndex$2(start, length);
4608 var fin = toAbsoluteIndex$2(end === undefined ? length : end, length);
4609 // inline `ArraySpeciesCreate` for usage native `Array#slice` where it's possible
4610 var Constructor, result, n;
4612 Constructor = O.constructor;
4613 // cross-realm fallback
4614 if (typeof Constructor == 'function' && (Constructor === Array || isArray$2(Constructor.prototype))) {
4615 Constructor = undefined;
4616 } else if (isObject$d(Constructor)) {
4617 Constructor = Constructor[SPECIES$1];
4618 if (Constructor === null) Constructor = undefined;
4620 if (Constructor === Array || Constructor === undefined) {
4621 return nativeSlice.call(O, k, fin);
4624 result = new (Constructor === undefined ? Array : Constructor)(max$3(fin - k, 0));
4625 for (n = 0; k < fin; k++, n++) if (k in O) createProperty$3(result, n, O[k]);
4631 var fails$s = fails$N;
4632 var wellKnownSymbol$7 = wellKnownSymbol$s;
4633 var IS_PURE = isPure;
4635 var ITERATOR$1 = wellKnownSymbol$7('iterator');
4637 var nativeUrl = !fails$s(function () {
4638 var url = new URL('b?a=1&b=2&c=3', 'http://a');
4639 var searchParams = url.searchParams;
4641 url.pathname = 'c%20d';
4642 searchParams.forEach(function (value, key) {
4643 searchParams['delete']('b');
4644 result += key + value;
4646 return (IS_PURE && !url.toJSON)
4647 || !searchParams.sort
4648 || url.href !== 'http://a/c%20d?a=1&c=3'
4649 || searchParams.get('c') !== '3'
4650 || String(new URLSearchParams('?a=1')) !== 'a=1'
4651 || !searchParams[ITERATOR$1]
4653 || new URL('https://a@b').username !== 'a'
4654 || new URLSearchParams(new URLSearchParams('a=b')).get('a') !== 'b'
4655 // not punycoded in Edge
4656 || new URL('http://тест').host !== 'xn--e1aybc'
4657 // not escaped in Chrome 62-
4658 || new URL('http://a#б').hash !== '#%D0%B1'
4659 // fails in Chrome 66-
4660 || result !== 'a1c3'
4662 || new URL('http://x', undefined).host !== 'x';
4665 var DESCRIPTORS$b = descriptors;
4666 var fails$r = fails$N;
4667 var objectKeys$1 = objectKeys$4;
4668 var getOwnPropertySymbolsModule = objectGetOwnPropertySymbols;
4669 var propertyIsEnumerableModule = objectPropertyIsEnumerable;
4670 var toObject$8 = toObject$i;
4671 var IndexedObject = indexedObject;
4673 // eslint-disable-next-line es/no-object-assign -- safe
4674 var $assign = Object.assign;
4675 // eslint-disable-next-line es/no-object-defineproperty -- required for testing
4676 var defineProperty$5 = Object.defineProperty;
4678 // `Object.assign` method
4679 // https://tc39.es/ecma262/#sec-object.assign
4680 var objectAssign = !$assign || fails$r(function () {
4681 // should have correct order of operations (Edge bug)
4682 if (DESCRIPTORS$b && $assign({ b: 1 }, $assign(defineProperty$5({}, 'a', {
4685 defineProperty$5(this, 'b', {
4690 }), { b: 2 })).b !== 1) return true;
4691 // should work with symbols and should have deterministic property order (V8 bug)
4694 // eslint-disable-next-line es/no-symbol -- safe
4695 var symbol = Symbol();
4696 var alphabet = 'abcdefghijklmnopqrst';
4698 alphabet.split('').forEach(function (chr) { B[chr] = chr; });
4699 return $assign({}, A)[symbol] != 7 || objectKeys$1($assign({}, B)).join('') != alphabet;
4700 }) ? function assign(target, source) { // eslint-disable-line no-unused-vars -- required for `.length`
4701 var T = toObject$8(target);
4702 var argumentsLength = arguments.length;
4704 var getOwnPropertySymbols = getOwnPropertySymbolsModule.f;
4705 var propertyIsEnumerable = propertyIsEnumerableModule.f;
4706 while (argumentsLength > index) {
4707 var S = IndexedObject(arguments[index++]);
4708 var keys = getOwnPropertySymbols ? objectKeys$1(S).concat(getOwnPropertySymbols(S)) : objectKeys$1(S);
4709 var length = keys.length;
4712 while (length > j) {
4714 if (!DESCRIPTORS$b || propertyIsEnumerable.call(S, key)) T[key] = S[key];
4719 var anObject$a = anObject$m;
4720 var iteratorClose = iteratorClose$2;
4722 // call something on iterator step with safe closing on error
4723 var callWithSafeIterationClosing$1 = function (iterator, fn, value, ENTRIES) {
4725 return ENTRIES ? fn(anObject$a(value)[0], value[1]) : fn(value);
4727 iteratorClose(iterator);
4732 var bind$6 = functionBindContext;
4733 var toObject$7 = toObject$i;
4734 var callWithSafeIterationClosing = callWithSafeIterationClosing$1;
4735 var isArrayIteratorMethod = isArrayIteratorMethod$3;
4736 var toLength$9 = toLength$q;
4737 var createProperty$2 = createProperty$4;
4738 var getIteratorMethod$2 = getIteratorMethod$5;
4740 // `Array.from` method implementation
4741 // https://tc39.es/ecma262/#sec-array.from
4742 var arrayFrom$1 = function from(arrayLike /* , mapfn = undefined, thisArg = undefined */) {
4743 var O = toObject$7(arrayLike);
4744 var C = typeof this == 'function' ? this : Array;
4745 var argumentsLength = arguments.length;
4746 var mapfn = argumentsLength > 1 ? arguments[1] : undefined;
4747 var mapping = mapfn !== undefined;
4748 var iteratorMethod = getIteratorMethod$2(O);
4750 var length, result, step, iterator, next, value;
4751 if (mapping) mapfn = bind$6(mapfn, argumentsLength > 2 ? arguments[2] : undefined, 2);
4752 // if the target is not iterable or it's an array with the default iterator - use a simple case
4753 if (iteratorMethod != undefined && !(C == Array && isArrayIteratorMethod(iteratorMethod))) {
4754 iterator = iteratorMethod.call(O);
4755 next = iterator.next;
4757 for (;!(step = next.call(iterator)).done; index++) {
4758 value = mapping ? callWithSafeIterationClosing(iterator, mapfn, [step.value, index], true) : step.value;
4759 createProperty$2(result, index, value);
4762 length = toLength$9(O.length);
4763 result = new C(length);
4764 for (;length > index; index++) {
4765 value = mapping ? mapfn(O[index], index) : O[index];
4766 createProperty$2(result, index, value);
4769 result.length = index;
4773 // based on https://github.com/bestiejs/punycode.js/blob/master/punycode.js
4774 var maxInt = 2147483647; // aka. 0x7FFFFFFF or 2^31-1
4780 var initialBias = 72;
4781 var initialN = 128; // 0x80
4782 var delimiter = '-'; // '\x2D'
4783 var regexNonASCII = /[^\0-\u007E]/; // non-ASCII chars
4784 var regexSeparators = /[.\u3002\uFF0E\uFF61]/g; // RFC 3490 separators
4785 var OVERFLOW_ERROR = 'Overflow: input needs wider integers to process';
4786 var baseMinusTMin = base - tMin;
4787 var floor$3 = Math.floor;
4788 var stringFromCharCode = String.fromCharCode;
4791 * Creates an array containing the numeric code points of each Unicode
4792 * character in the string. While JavaScript uses UCS-2 internally,
4793 * this function will convert a pair of surrogate halves (each of which
4794 * UCS-2 exposes as separate characters) into a single code point,
4797 var ucs2decode = function (string) {
4800 var length = string.length;
4801 while (counter < length) {
4802 var value = string.charCodeAt(counter++);
4803 if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
4804 // It's a high surrogate, and there is a next character.
4805 var extra = string.charCodeAt(counter++);
4806 if ((extra & 0xFC00) == 0xDC00) { // Low surrogate.
4807 output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
4809 // It's an unmatched surrogate; only append this code unit, in case the
4810 // next code unit is the high surrogate of a surrogate pair.
4822 * Converts a digit/integer into a basic code point.
4824 var digitToBasic = function (digit) {
4825 // 0..25 map to ASCII a..z or A..Z
4826 // 26..35 map to ASCII 0..9
4827 return digit + 22 + 75 * (digit < 26);
4831 * Bias adaptation function as per section 3.4 of RFC 3492.
4832 * https://tools.ietf.org/html/rfc3492#section-3.4
4834 var adapt = function (delta, numPoints, firstTime) {
4836 delta = firstTime ? floor$3(delta / damp) : delta >> 1;
4837 delta += floor$3(delta / numPoints);
4838 for (; delta > baseMinusTMin * tMax >> 1; k += base) {
4839 delta = floor$3(delta / baseMinusTMin);
4841 return floor$3(k + (baseMinusTMin + 1) * delta / (delta + skew));
4845 * Converts a string of Unicode symbols (e.g. a domain name label) to a
4846 * Punycode string of ASCII-only symbols.
4848 // eslint-disable-next-line max-statements -- TODO
4849 var encode = function (input) {
4852 // Convert the input in UCS-2 to an array of Unicode code points.
4853 input = ucs2decode(input);
4855 // Cache the length.
4856 var inputLength = input.length;
4858 // Initialize the state.
4861 var bias = initialBias;
4862 var i, currentValue;
4864 // Handle the basic code points.
4865 for (i = 0; i < input.length; i++) {
4866 currentValue = input[i];
4867 if (currentValue < 0x80) {
4868 output.push(stringFromCharCode(currentValue));
4872 var basicLength = output.length; // number of basic code points.
4873 var handledCPCount = basicLength; // number of code points that have been handled;
4875 // Finish the basic string with a delimiter unless it's empty.
4877 output.push(delimiter);
4880 // Main encoding loop:
4881 while (handledCPCount < inputLength) {
4882 // All non-basic code points < n have been handled already. Find the next larger one:
4884 for (i = 0; i < input.length; i++) {
4885 currentValue = input[i];
4886 if (currentValue >= n && currentValue < m) {
4891 // Increase `delta` enough to advance the decoder's <n,i> state to <m,0>, but guard against overflow.
4892 var handledCPCountPlusOne = handledCPCount + 1;
4893 if (m - n > floor$3((maxInt - delta) / handledCPCountPlusOne)) {
4894 throw RangeError(OVERFLOW_ERROR);
4897 delta += (m - n) * handledCPCountPlusOne;
4900 for (i = 0; i < input.length; i++) {
4901 currentValue = input[i];
4902 if (currentValue < n && ++delta > maxInt) {
4903 throw RangeError(OVERFLOW_ERROR);
4905 if (currentValue == n) {
4906 // Represent delta as a generalized variable-length integer.
4908 for (var k = base; /* no condition */; k += base) {
4909 var t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
4911 var qMinusT = q - t;
4912 var baseMinusT = base - t;
4913 output.push(stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT)));
4914 q = floor$3(qMinusT / baseMinusT);
4917 output.push(stringFromCharCode(digitToBasic(q)));
4918 bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
4927 return output.join('');
4930 var stringPunycodeToAscii = function (input) {
4932 var labels = input.toLowerCase().replace(regexSeparators, '\u002E').split('.');
4934 for (i = 0; i < labels.length; i++) {
4936 encoded.push(regexNonASCII.test(label) ? 'xn--' + encode(label) : label);
4938 return encoded.join('.');
4941 var anObject$9 = anObject$m;
4942 var getIteratorMethod$1 = getIteratorMethod$5;
4944 var getIterator$1 = function (it) {
4945 var iteratorMethod = getIteratorMethod$1(it);
4946 if (typeof iteratorMethod != 'function') {
4947 throw TypeError(String(it) + ' is not iterable');
4948 } return anObject$9(iteratorMethod.call(it));
4951 // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
4954 var getBuiltIn$2 = getBuiltIn$9;
4955 var USE_NATIVE_URL$1 = nativeUrl;
4956 var redefine$7 = redefine$g.exports;
4957 var redefineAll$1 = redefineAll$4;
4958 var setToStringTag$4 = setToStringTag$a;
4959 var createIteratorConstructor = createIteratorConstructor$2;
4960 var InternalStateModule$2 = internalState;
4961 var anInstance$3 = anInstance$7;
4963 var bind$5 = functionBindContext;
4964 var classof$4 = classof$b;
4965 var anObject$8 = anObject$m;
4966 var isObject$c = isObject$r;
4967 var create$8 = objectCreate;
4968 var createPropertyDescriptor = createPropertyDescriptor$7;
4969 var getIterator = getIterator$1;
4970 var getIteratorMethod = getIteratorMethod$5;
4971 var wellKnownSymbol$6 = wellKnownSymbol$s;
4973 var $fetch = getBuiltIn$2('fetch');
4974 var Headers$1 = getBuiltIn$2('Headers');
4975 var ITERATOR = wellKnownSymbol$6('iterator');
4976 var URL_SEARCH_PARAMS = 'URLSearchParams';
4977 var URL_SEARCH_PARAMS_ITERATOR = URL_SEARCH_PARAMS + 'Iterator';
4978 var setInternalState$2 = InternalStateModule$2.set;
4979 var getInternalParamsState = InternalStateModule$2.getterFor(URL_SEARCH_PARAMS);
4980 var getInternalIteratorState = InternalStateModule$2.getterFor(URL_SEARCH_PARAMS_ITERATOR);
4983 var sequences = Array(4);
4985 var percentSequence = function (bytes) {
4986 return sequences[bytes - 1] || (sequences[bytes - 1] = RegExp('((?:%[\\da-f]{2}){' + bytes + '})', 'gi'));
4989 var percentDecode = function (sequence) {
4991 return decodeURIComponent(sequence);
4997 var deserialize = function (it) {
4998 var result = it.replace(plus, ' ');
5001 return decodeURIComponent(result);
5004 result = result.replace(percentSequence(bytes--), percentDecode);
5010 var find$1 = /[!'()~]|%20/g;
5021 var replacer = function (match) {
5022 return replace$1[match];
5025 var serialize = function (it) {
5026 return encodeURIComponent(it).replace(find$1, replacer);
5029 var parseSearchParams = function (result, query) {
5031 var attributes = query.split('&');
5033 var attribute, entry;
5034 while (index < attributes.length) {
5035 attribute = attributes[index++];
5036 if (attribute.length) {
5037 entry = attribute.split('=');
5039 key: deserialize(entry.shift()),
5040 value: deserialize(entry.join('='))
5047 var updateSearchParams = function (query) {
5048 this.entries.length = 0;
5049 parseSearchParams(this.entries, query);
5052 var validateArgumentsLength = function (passed, required) {
5053 if (passed < required) throw TypeError('Not enough arguments');
5056 var URLSearchParamsIterator = createIteratorConstructor(function Iterator(params, kind) {
5057 setInternalState$2(this, {
5058 type: URL_SEARCH_PARAMS_ITERATOR,
5059 iterator: getIterator(getInternalParamsState(params).entries),
5062 }, 'Iterator', function next() {
5063 var state = getInternalIteratorState(this);
5064 var kind = state.kind;
5065 var step = state.iterator.next();
5066 var entry = step.value;
5068 step.value = kind === 'keys' ? entry.key : kind === 'values' ? entry.value : [entry.key, entry.value];
5072 // `URLSearchParams` constructor
5073 // https://url.spec.whatwg.org/#interface-urlsearchparams
5074 var URLSearchParamsConstructor = function URLSearchParams(/* init */) {
5075 anInstance$3(this, URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5076 var init = arguments.length > 0 ? arguments[0] : undefined;
5079 var iteratorMethod, iterator, next, step, entryIterator, entryNext, first, second, key;
5081 setInternalState$2(that, {
5082 type: URL_SEARCH_PARAMS,
5084 updateURL: function () { /* empty */ },
5085 updateSearchParams: updateSearchParams
5088 if (init !== undefined) {
5089 if (isObject$c(init)) {
5090 iteratorMethod = getIteratorMethod(init);
5091 if (typeof iteratorMethod === 'function') {
5092 iterator = iteratorMethod.call(init);
5093 next = iterator.next;
5094 while (!(step = next.call(iterator)).done) {
5095 entryIterator = getIterator(anObject$8(step.value));
5096 entryNext = entryIterator.next;
5098 (first = entryNext.call(entryIterator)).done ||
5099 (second = entryNext.call(entryIterator)).done ||
5100 !entryNext.call(entryIterator).done
5101 ) throw TypeError('Expected sequence with length 2');
5102 entries.push({ key: first.value + '', value: second.value + '' });
5104 } else for (key in init) if (hasOwn(init, key)) entries.push({ key: key, value: init[key] + '' });
5106 parseSearchParams(entries, typeof init === 'string' ? init.charAt(0) === '?' ? init.slice(1) : init : init + '');
5111 var URLSearchParamsPrototype = URLSearchParamsConstructor.prototype;
5113 redefineAll$1(URLSearchParamsPrototype, {
5114 // `URLSearchParams.prototype.append` method
5115 // https://url.spec.whatwg.org/#dom-urlsearchparams-append
5116 append: function append(name, value) {
5117 validateArgumentsLength(arguments.length, 2);
5118 var state = getInternalParamsState(this);
5119 state.entries.push({ key: name + '', value: value + '' });
5122 // `URLSearchParams.prototype.delete` method
5123 // https://url.spec.whatwg.org/#dom-urlsearchparams-delete
5124 'delete': function (name) {
5125 validateArgumentsLength(arguments.length, 1);
5126 var state = getInternalParamsState(this);
5127 var entries = state.entries;
5128 var key = name + '';
5130 while (index < entries.length) {
5131 if (entries[index].key === key) entries.splice(index, 1);
5136 // `URLSearchParams.prototype.get` method
5137 // https://url.spec.whatwg.org/#dom-urlsearchparams-get
5138 get: function get(name) {
5139 validateArgumentsLength(arguments.length, 1);
5140 var entries = getInternalParamsState(this).entries;
5141 var key = name + '';
5143 for (; index < entries.length; index++) {
5144 if (entries[index].key === key) return entries[index].value;
5148 // `URLSearchParams.prototype.getAll` method
5149 // https://url.spec.whatwg.org/#dom-urlsearchparams-getall
5150 getAll: function getAll(name) {
5151 validateArgumentsLength(arguments.length, 1);
5152 var entries = getInternalParamsState(this).entries;
5153 var key = name + '';
5156 for (; index < entries.length; index++) {
5157 if (entries[index].key === key) result.push(entries[index].value);
5161 // `URLSearchParams.prototype.has` method
5162 // https://url.spec.whatwg.org/#dom-urlsearchparams-has
5163 has: function has(name) {
5164 validateArgumentsLength(arguments.length, 1);
5165 var entries = getInternalParamsState(this).entries;
5166 var key = name + '';
5168 while (index < entries.length) {
5169 if (entries[index++].key === key) return true;
5173 // `URLSearchParams.prototype.set` method
5174 // https://url.spec.whatwg.org/#dom-urlsearchparams-set
5175 set: function set(name, value) {
5176 validateArgumentsLength(arguments.length, 1);
5177 var state = getInternalParamsState(this);
5178 var entries = state.entries;
5180 var key = name + '';
5181 var val = value + '';
5184 for (; index < entries.length; index++) {
5185 entry = entries[index];
5186 if (entry.key === key) {
5187 if (found) entries.splice(index--, 1);
5194 if (!found) entries.push({ key: key, value: val });
5197 // `URLSearchParams.prototype.sort` method
5198 // https://url.spec.whatwg.org/#dom-urlsearchparams-sort
5199 sort: function sort() {
5200 var state = getInternalParamsState(this);
5201 var entries = state.entries;
5202 // Array#sort is not stable in some engines
5203 var slice = entries.slice();
5204 var entry, entriesIndex, sliceIndex;
5206 for (sliceIndex = 0; sliceIndex < slice.length; sliceIndex++) {
5207 entry = slice[sliceIndex];
5208 for (entriesIndex = 0; entriesIndex < sliceIndex; entriesIndex++) {
5209 if (entries[entriesIndex].key > entry.key) {
5210 entries.splice(entriesIndex, 0, entry);
5214 if (entriesIndex === sliceIndex) entries.push(entry);
5218 // `URLSearchParams.prototype.forEach` method
5219 forEach: function forEach(callback /* , thisArg */) {
5220 var entries = getInternalParamsState(this).entries;
5221 var boundFunction = bind$5(callback, arguments.length > 1 ? arguments[1] : undefined, 3);
5224 while (index < entries.length) {
5225 entry = entries[index++];
5226 boundFunction(entry.value, entry.key, this);
5229 // `URLSearchParams.prototype.keys` method
5230 keys: function keys() {
5231 return new URLSearchParamsIterator(this, 'keys');
5233 // `URLSearchParams.prototype.values` method
5234 values: function values() {
5235 return new URLSearchParamsIterator(this, 'values');
5237 // `URLSearchParams.prototype.entries` method
5238 entries: function entries() {
5239 return new URLSearchParamsIterator(this, 'entries');
5241 }, { enumerable: true });
5243 // `URLSearchParams.prototype[@@iterator]` method
5244 redefine$7(URLSearchParamsPrototype, ITERATOR, URLSearchParamsPrototype.entries);
5246 // `URLSearchParams.prototype.toString` method
5247 // https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
5248 redefine$7(URLSearchParamsPrototype, 'toString', function toString() {
5249 var entries = getInternalParamsState(this).entries;
5253 while (index < entries.length) {
5254 entry = entries[index++];
5255 result.push(serialize(entry.key) + '=' + serialize(entry.value));
5256 } return result.join('&');
5257 }, { enumerable: true });
5259 setToStringTag$4(URLSearchParamsConstructor, URL_SEARCH_PARAMS);
5261 $$R({ global: true, forced: !USE_NATIVE_URL$1 }, {
5262 URLSearchParams: URLSearchParamsConstructor
5265 // Wrap `fetch` for correct work with polyfilled `URLSearchParams`
5266 // https://github.com/zloirock/core-js/issues/674
5267 if (!USE_NATIVE_URL$1 && typeof $fetch == 'function' && typeof Headers$1 == 'function') {
5268 $$R({ global: true, enumerable: true, forced: true }, {
5269 fetch: function fetch(input /* , init */) {
5271 var init, body, headers;
5272 if (arguments.length > 1) {
5273 init = arguments[1];
5274 if (isObject$c(init)) {
5276 if (classof$4(body) === URL_SEARCH_PARAMS) {
5277 headers = init.headers ? new Headers$1(init.headers) : new Headers$1();
5278 if (!headers.has('content-type')) {
5279 headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
5281 init = create$8(init, {
5282 body: createPropertyDescriptor(0, String(body)),
5283 headers: createPropertyDescriptor(0, headers)
5288 } return $fetch.apply(this, args);
5293 var web_urlSearchParams = {
5294 URLSearchParams: URLSearchParamsConstructor,
5295 getState: getInternalParamsState
5298 // TODO: in core-js@4, move /modules/ dependencies to public entries for better optimization by tools like `preset-env`
5301 var DESCRIPTORS$a = descriptors;
5302 var USE_NATIVE_URL = nativeUrl;
5303 var global$a = global$F;
5304 var defineProperties$1 = objectDefineProperties;
5305 var redefine$6 = redefine$g.exports;
5306 var anInstance$2 = anInstance$7;
5308 var assign$2 = objectAssign;
5309 var arrayFrom = arrayFrom$1;
5310 var codeAt = stringMultibyte.codeAt;
5311 var toASCII = stringPunycodeToAscii;
5312 var setToStringTag$3 = setToStringTag$a;
5313 var URLSearchParamsModule = web_urlSearchParams;
5314 var InternalStateModule$1 = internalState;
5316 var NativeURL = global$a.URL;
5317 var URLSearchParams$1 = URLSearchParamsModule.URLSearchParams;
5318 var getInternalSearchParamsState = URLSearchParamsModule.getState;
5319 var setInternalState$1 = InternalStateModule$1.set;
5320 var getInternalURLState = InternalStateModule$1.getterFor('URL');
5321 var floor$2 = Math.floor;
5322 var pow$1 = Math.pow;
5324 var INVALID_AUTHORITY = 'Invalid authority';
5325 var INVALID_SCHEME = 'Invalid scheme';
5326 var INVALID_HOST = 'Invalid host';
5327 var INVALID_PORT = 'Invalid port';
5329 var ALPHA = /[A-Za-z]/;
5330 // eslint-disable-next-line regexp/no-obscure-range -- safe
5331 var ALPHANUMERIC = /[\d+-.A-Za-z]/;
5333 var HEX_START = /^0x/i;
5334 var OCT = /^[0-7]+$/;
5336 var HEX = /^[\dA-Fa-f]+$/;
5337 /* eslint-disable no-control-regex -- safe */
5338 var FORBIDDEN_HOST_CODE_POINT = /[\0\t\n\r #%/:<>?@[\\\]^|]/;
5339 var FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT = /[\0\t\n\r #/:<>?@[\\\]^|]/;
5340 var LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE = /^[\u0000-\u001F ]+|[\u0000-\u001F ]+$/g;
5341 var TAB_AND_NEW_LINE = /[\t\n\r]/g;
5342 /* eslint-enable no-control-regex -- safe */
5345 var parseHost = function (url, input) {
5346 var result, codePoints, index;
5347 if (input.charAt(0) == '[') {
5348 if (input.charAt(input.length - 1) != ']') return INVALID_HOST;
5349 result = parseIPv6(input.slice(1, -1));
5350 if (!result) return INVALID_HOST;
5353 } else if (!isSpecial(url)) {
5354 if (FORBIDDEN_HOST_CODE_POINT_EXCLUDING_PERCENT.test(input)) return INVALID_HOST;
5356 codePoints = arrayFrom(input);
5357 for (index = 0; index < codePoints.length; index++) {
5358 result += percentEncode(codePoints[index], C0ControlPercentEncodeSet);
5362 input = toASCII(input);
5363 if (FORBIDDEN_HOST_CODE_POINT.test(input)) return INVALID_HOST;
5364 result = parseIPv4(input);
5365 if (result === null) return INVALID_HOST;
5370 var parseIPv4 = function (input) {
5371 var parts = input.split('.');
5372 var partsLength, numbers, index, part, radix, number, ipv4;
5373 if (parts.length && parts[parts.length - 1] == '') {
5376 partsLength = parts.length;
5377 if (partsLength > 4) return input;
5379 for (index = 0; index < partsLength; index++) {
5380 part = parts[index];
5381 if (part == '') return input;
5383 if (part.length > 1 && part.charAt(0) == '0') {
5384 radix = HEX_START.test(part) ? 16 : 8;
5385 part = part.slice(radix == 8 ? 1 : 2);
5390 if (!(radix == 10 ? DEC : radix == 8 ? OCT : HEX).test(part)) return input;
5391 number = parseInt(part, radix);
5393 numbers.push(number);
5395 for (index = 0; index < partsLength; index++) {
5396 number = numbers[index];
5397 if (index == partsLength - 1) {
5398 if (number >= pow$1(256, 5 - partsLength)) return null;
5399 } else if (number > 255) return null;
5401 ipv4 = numbers.pop();
5402 for (index = 0; index < numbers.length; index++) {
5403 ipv4 += numbers[index] * pow$1(256, 3 - index);
5408 // eslint-disable-next-line max-statements -- TODO
5409 var parseIPv6 = function (input) {
5410 var address = [0, 0, 0, 0, 0, 0, 0, 0];
5412 var compress = null;
5414 var value, length, numbersSeen, ipv4Piece, number, swaps, swap;
5416 var char = function () {
5417 return input.charAt(pointer);
5420 if (char() == ':') {
5421 if (input.charAt(1) != ':') return;
5424 compress = pieceIndex;
5427 if (pieceIndex == 8) return;
5428 if (char() == ':') {
5429 if (compress !== null) return;
5432 compress = pieceIndex;
5436 while (length < 4 && HEX.test(char())) {
5437 value = value * 16 + parseInt(char(), 16);
5441 if (char() == '.') {
5442 if (length == 0) return;
5444 if (pieceIndex > 6) return;
5448 if (numbersSeen > 0) {
5449 if (char() == '.' && numbersSeen < 4) pointer++;
5452 if (!DIGIT.test(char())) return;
5453 while (DIGIT.test(char())) {
5454 number = parseInt(char(), 10);
5455 if (ipv4Piece === null) ipv4Piece = number;
5456 else if (ipv4Piece == 0) return;
5457 else ipv4Piece = ipv4Piece * 10 + number;
5458 if (ipv4Piece > 255) return;
5461 address[pieceIndex] = address[pieceIndex] * 256 + ipv4Piece;
5463 if (numbersSeen == 2 || numbersSeen == 4) pieceIndex++;
5465 if (numbersSeen != 4) return;
5467 } else if (char() == ':') {
5469 if (!char()) return;
5470 } else if (char()) return;
5471 address[pieceIndex++] = value;
5473 if (compress !== null) {
5474 swaps = pieceIndex - compress;
5476 while (pieceIndex != 0 && swaps > 0) {
5477 swap = address[pieceIndex];
5478 address[pieceIndex--] = address[compress + swaps - 1];
5479 address[compress + --swaps] = swap;
5481 } else if (pieceIndex != 8) return;
5485 var findLongestZeroSequence = function (ipv6) {
5486 var maxIndex = null;
5488 var currStart = null;
5491 for (; index < 8; index++) {
5492 if (ipv6[index] !== 0) {
5493 if (currLength > maxLength) {
5494 maxIndex = currStart;
5495 maxLength = currLength;
5500 if (currStart === null) currStart = index;
5504 if (currLength > maxLength) {
5505 maxIndex = currStart;
5506 maxLength = currLength;
5511 var serializeHost = function (host) {
5512 var result, index, compress, ignore0;
5514 if (typeof host == 'number') {
5516 for (index = 0; index < 4; index++) {
5517 result.unshift(host % 256);
5518 host = floor$2(host / 256);
5519 } return result.join('.');
5521 } else if (typeof host == 'object') {
5523 compress = findLongestZeroSequence(host);
5524 for (index = 0; index < 8; index++) {
5525 if (ignore0 && host[index] === 0) continue;
5526 if (ignore0) ignore0 = false;
5527 if (compress === index) {
5528 result += index ? ':' : '::';
5531 result += host[index].toString(16);
5532 if (index < 7) result += ':';
5535 return '[' + result + ']';
5539 var C0ControlPercentEncodeSet = {};
5540 var fragmentPercentEncodeSet = assign$2({}, C0ControlPercentEncodeSet, {
5541 ' ': 1, '"': 1, '<': 1, '>': 1, '`': 1
5543 var pathPercentEncodeSet = assign$2({}, fragmentPercentEncodeSet, {
5544 '#': 1, '?': 1, '{': 1, '}': 1
5546 var userinfoPercentEncodeSet = assign$2({}, pathPercentEncodeSet, {
5547 '/': 1, ':': 1, ';': 1, '=': 1, '@': 1, '[': 1, '\\': 1, ']': 1, '^': 1, '|': 1
5550 var percentEncode = function (char, set) {
5551 var code = codeAt(char, 0);
5552 return code > 0x20 && code < 0x7F && !has$4(set, char) ? char : encodeURIComponent(char);
5555 var specialSchemes = {
5564 var isSpecial = function (url) {
5565 return has$4(specialSchemes, url.scheme);
5568 var includesCredentials = function (url) {
5569 return url.username != '' || url.password != '';
5572 var cannotHaveUsernamePasswordPort = function (url) {
5573 return !url.host || url.cannotBeABaseURL || url.scheme == 'file';
5576 var isWindowsDriveLetter = function (string, normalized) {
5578 return string.length == 2 && ALPHA.test(string.charAt(0))
5579 && ((second = string.charAt(1)) == ':' || (!normalized && second == '|'));
5582 var startsWithWindowsDriveLetter = function (string) {
5584 return string.length > 1 && isWindowsDriveLetter(string.slice(0, 2)) && (
5585 string.length == 2 ||
5586 ((third = string.charAt(2)) === '/' || third === '\\' || third === '?' || third === '#')
5590 var shortenURLsPath = function (url) {
5591 var path = url.path;
5592 var pathSize = path.length;
5593 if (pathSize && (url.scheme != 'file' || pathSize != 1 || !isWindowsDriveLetter(path[0], true))) {
5598 var isSingleDot = function (segment) {
5599 return segment === '.' || segment.toLowerCase() === '%2e';
5602 var isDoubleDot = function (segment) {
5603 segment = segment.toLowerCase();
5604 return segment === '..' || segment === '%2e.' || segment === '.%2e' || segment === '%2e%2e';
5608 var SCHEME_START = {};
5611 var SPECIAL_RELATIVE_OR_AUTHORITY = {};
5612 var PATH_OR_AUTHORITY = {};
5614 var RELATIVE_SLASH = {};
5615 var SPECIAL_AUTHORITY_SLASHES = {};
5616 var SPECIAL_AUTHORITY_IGNORE_SLASHES = {};
5622 var FILE_SLASH = {};
5624 var PATH_START = {};
5626 var CANNOT_BE_A_BASE_URL_PATH = {};
5630 // eslint-disable-next-line max-statements -- TODO
5631 var parseURL = function (url, input, stateOverride, base) {
5632 var state = stateOverride || SCHEME_START;
5636 var seenBracket = false;
5637 var seenPasswordToken = false;
5638 var codePoints, char, bufferCodePoints, failure;
5640 if (!stateOverride) {
5648 url.fragment = null;
5649 url.cannotBeABaseURL = false;
5650 input = input.replace(LEADING_AND_TRAILING_C0_CONTROL_OR_SPACE, '');
5653 input = input.replace(TAB_AND_NEW_LINE, '');
5655 codePoints = arrayFrom(input);
5657 while (pointer <= codePoints.length) {
5658 char = codePoints[pointer];
5661 if (char && ALPHA.test(char)) {
5662 buffer += char.toLowerCase();
5664 } else if (!stateOverride) {
5667 } else return INVALID_SCHEME;
5671 if (char && (ALPHANUMERIC.test(char) || char == '+' || char == '-' || char == '.')) {
5672 buffer += char.toLowerCase();
5673 } else if (char == ':') {
5674 if (stateOverride && (
5675 (isSpecial(url) != has$4(specialSchemes, buffer)) ||
5676 (buffer == 'file' && (includesCredentials(url) || url.port !== null)) ||
5677 (url.scheme == 'file' && !url.host)
5679 url.scheme = buffer;
5680 if (stateOverride) {
5681 if (isSpecial(url) && specialSchemes[url.scheme] == url.port) url.port = null;
5685 if (url.scheme == 'file') {
5687 } else if (isSpecial(url) && base && base.scheme == url.scheme) {
5688 state = SPECIAL_RELATIVE_OR_AUTHORITY;
5689 } else if (isSpecial(url)) {
5690 state = SPECIAL_AUTHORITY_SLASHES;
5691 } else if (codePoints[pointer + 1] == '/') {
5692 state = PATH_OR_AUTHORITY;
5695 url.cannotBeABaseURL = true;
5697 state = CANNOT_BE_A_BASE_URL_PATH;
5699 } else if (!stateOverride) {
5704 } else return INVALID_SCHEME;
5708 if (!base || (base.cannotBeABaseURL && char != '#')) return INVALID_SCHEME;
5709 if (base.cannotBeABaseURL && char == '#') {
5710 url.scheme = base.scheme;
5711 url.path = base.path.slice();
5712 url.query = base.query;
5714 url.cannotBeABaseURL = true;
5718 state = base.scheme == 'file' ? FILE : RELATIVE;
5721 case SPECIAL_RELATIVE_OR_AUTHORITY:
5722 if (char == '/' && codePoints[pointer + 1] == '/') {
5723 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5730 case PATH_OR_AUTHORITY:
5740 url.scheme = base.scheme;
5742 url.username = base.username;
5743 url.password = base.password;
5744 url.host = base.host;
5745 url.port = base.port;
5746 url.path = base.path.slice();
5747 url.query = base.query;
5748 } else if (char == '/' || (char == '\\' && isSpecial(url))) {
5749 state = RELATIVE_SLASH;
5750 } else if (char == '?') {
5751 url.username = base.username;
5752 url.password = base.password;
5753 url.host = base.host;
5754 url.port = base.port;
5755 url.path = base.path.slice();
5758 } else if (char == '#') {
5759 url.username = base.username;
5760 url.password = base.password;
5761 url.host = base.host;
5762 url.port = base.port;
5763 url.path = base.path.slice();
5764 url.query = base.query;
5768 url.username = base.username;
5769 url.password = base.password;
5770 url.host = base.host;
5771 url.port = base.port;
5772 url.path = base.path.slice();
5778 case RELATIVE_SLASH:
5779 if (isSpecial(url) && (char == '/' || char == '\\')) {
5780 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5781 } else if (char == '/') {
5784 url.username = base.username;
5785 url.password = base.password;
5786 url.host = base.host;
5787 url.port = base.port;
5792 case SPECIAL_AUTHORITY_SLASHES:
5793 state = SPECIAL_AUTHORITY_IGNORE_SLASHES;
5794 if (char != '/' || buffer.charAt(pointer + 1) != '/') continue;
5798 case SPECIAL_AUTHORITY_IGNORE_SLASHES:
5799 if (char != '/' && char != '\\') {
5806 if (seenAt) buffer = '%40' + buffer;
5808 bufferCodePoints = arrayFrom(buffer);
5809 for (var i = 0; i < bufferCodePoints.length; i++) {
5810 var codePoint = bufferCodePoints[i];
5811 if (codePoint == ':' && !seenPasswordToken) {
5812 seenPasswordToken = true;
5815 var encodedCodePoints = percentEncode(codePoint, userinfoPercentEncodeSet);
5816 if (seenPasswordToken) url.password += encodedCodePoints;
5817 else url.username += encodedCodePoints;
5821 char == EOF || char == '/' || char == '?' || char == '#' ||
5822 (char == '\\' && isSpecial(url))
5824 if (seenAt && buffer == '') return INVALID_AUTHORITY;
5825 pointer -= arrayFrom(buffer).length + 1;
5828 } else buffer += char;
5833 if (stateOverride && url.scheme == 'file') {
5836 } else if (char == ':' && !seenBracket) {
5837 if (buffer == '') return INVALID_HOST;
5838 failure = parseHost(url, buffer);
5839 if (failure) return failure;
5842 if (stateOverride == HOSTNAME) return;
5844 char == EOF || char == '/' || char == '?' || char == '#' ||
5845 (char == '\\' && isSpecial(url))
5847 if (isSpecial(url) && buffer == '') return INVALID_HOST;
5848 if (stateOverride && buffer == '' && (includesCredentials(url) || url.port !== null)) return;
5849 failure = parseHost(url, buffer);
5850 if (failure) return failure;
5853 if (stateOverride) return;
5856 if (char == '[') seenBracket = true;
5857 else if (char == ']') seenBracket = false;
5862 if (DIGIT.test(char)) {
5865 char == EOF || char == '/' || char == '?' || char == '#' ||
5866 (char == '\\' && isSpecial(url)) ||
5870 var port = parseInt(buffer, 10);
5871 if (port > 0xFFFF) return INVALID_PORT;
5872 url.port = (isSpecial(url) && port === specialSchemes[url.scheme]) ? null : port;
5875 if (stateOverride) return;
5878 } else return INVALID_PORT;
5882 url.scheme = 'file';
5883 if (char == '/' || char == '\\') state = FILE_SLASH;
5884 else if (base && base.scheme == 'file') {
5886 url.host = base.host;
5887 url.path = base.path.slice();
5888 url.query = base.query;
5889 } else if (char == '?') {
5890 url.host = base.host;
5891 url.path = base.path.slice();
5894 } else if (char == '#') {
5895 url.host = base.host;
5896 url.path = base.path.slice();
5897 url.query = base.query;
5901 if (!startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5902 url.host = base.host;
5903 url.path = base.path.slice();
5904 shortenURLsPath(url);
5915 if (char == '/' || char == '\\') {
5919 if (base && base.scheme == 'file' && !startsWithWindowsDriveLetter(codePoints.slice(pointer).join(''))) {
5920 if (isWindowsDriveLetter(base.path[0], true)) url.path.push(base.path[0]);
5921 else url.host = base.host;
5927 if (char == EOF || char == '/' || char == '\\' || char == '?' || char == '#') {
5928 if (!stateOverride && isWindowsDriveLetter(buffer)) {
5930 } else if (buffer == '') {
5932 if (stateOverride) return;
5935 failure = parseHost(url, buffer);
5936 if (failure) return failure;
5937 if (url.host == 'localhost') url.host = '';
5938 if (stateOverride) return;
5942 } else buffer += char;
5946 if (isSpecial(url)) {
5948 if (char != '/' && char != '\\') continue;
5949 } else if (!stateOverride && char == '?') {
5952 } else if (!stateOverride && char == '#') {
5955 } else if (char != EOF) {
5957 if (char != '/') continue;
5962 char == EOF || char == '/' ||
5963 (char == '\\' && isSpecial(url)) ||
5964 (!stateOverride && (char == '?' || char == '#'))
5966 if (isDoubleDot(buffer)) {
5967 shortenURLsPath(url);
5968 if (char != '/' && !(char == '\\' && isSpecial(url))) {
5971 } else if (isSingleDot(buffer)) {
5972 if (char != '/' && !(char == '\\' && isSpecial(url))) {
5976 if (url.scheme == 'file' && !url.path.length && isWindowsDriveLetter(buffer)) {
5977 if (url.host) url.host = '';
5978 buffer = buffer.charAt(0) + ':'; // normalize windows drive letter
5980 url.path.push(buffer);
5983 if (url.scheme == 'file' && (char == EOF || char == '?' || char == '#')) {
5984 while (url.path.length > 1 && url.path[0] === '') {
5991 } else if (char == '#') {
5996 buffer += percentEncode(char, pathPercentEncodeSet);
5999 case CANNOT_BE_A_BASE_URL_PATH:
6003 } else if (char == '#') {
6006 } else if (char != EOF) {
6007 url.path[0] += percentEncode(char, C0ControlPercentEncodeSet);
6011 if (!stateOverride && char == '#') {
6014 } else if (char != EOF) {
6015 if (char == "'" && isSpecial(url)) url.query += '%27';
6016 else if (char == '#') url.query += '%23';
6017 else url.query += percentEncode(char, C0ControlPercentEncodeSet);
6021 if (char != EOF) url.fragment += percentEncode(char, fragmentPercentEncodeSet);
6029 // `URL` constructor
6030 // https://url.spec.whatwg.org/#url-class
6031 var URLConstructor = function URL(url /* , base */) {
6032 var that = anInstance$2(this, URLConstructor, 'URL');
6033 var base = arguments.length > 1 ? arguments[1] : undefined;
6034 var urlString = String(url);
6035 var state = setInternalState$1(that, { type: 'URL' });
6036 var baseState, failure;
6037 if (base !== undefined) {
6038 if (base instanceof URLConstructor) baseState = getInternalURLState(base);
6040 failure = parseURL(baseState = {}, String(base));
6041 if (failure) throw TypeError(failure);
6044 failure = parseURL(state, urlString, null, baseState);
6045 if (failure) throw TypeError(failure);
6046 var searchParams = state.searchParams = new URLSearchParams$1();
6047 var searchParamsState = getInternalSearchParamsState(searchParams);
6048 searchParamsState.updateSearchParams(state.query);
6049 searchParamsState.updateURL = function () {
6050 state.query = String(searchParams) || null;
6052 if (!DESCRIPTORS$a) {
6053 that.href = serializeURL.call(that);
6054 that.origin = getOrigin.call(that);
6055 that.protocol = getProtocol.call(that);
6056 that.username = getUsername.call(that);
6057 that.password = getPassword.call(that);
6058 that.host = getHost.call(that);
6059 that.hostname = getHostname.call(that);
6060 that.port = getPort.call(that);
6061 that.pathname = getPathname.call(that);
6062 that.search = getSearch.call(that);
6063 that.searchParams = getSearchParams.call(that);
6064 that.hash = getHash.call(that);
6068 var URLPrototype = URLConstructor.prototype;
6070 var serializeURL = function () {
6071 var url = getInternalURLState(this);
6072 var scheme = url.scheme;
6073 var username = url.username;
6074 var password = url.password;
6075 var host = url.host;
6076 var port = url.port;
6077 var path = url.path;
6078 var query = url.query;
6079 var fragment = url.fragment;
6080 var output = scheme + ':';
6081 if (host !== null) {
6083 if (includesCredentials(url)) {
6084 output += username + (password ? ':' + password : '') + '@';
6086 output += serializeHost(host);
6087 if (port !== null) output += ':' + port;
6088 } else if (scheme == 'file') output += '//';
6089 output += url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
6090 if (query !== null) output += '?' + query;
6091 if (fragment !== null) output += '#' + fragment;
6095 var getOrigin = function () {
6096 var url = getInternalURLState(this);
6097 var scheme = url.scheme;
6098 var port = url.port;
6099 if (scheme == 'blob') try {
6100 return new URLConstructor(scheme.path[0]).origin;
6104 if (scheme == 'file' || !isSpecial(url)) return 'null';
6105 return scheme + '://' + serializeHost(url.host) + (port !== null ? ':' + port : '');
6108 var getProtocol = function () {
6109 return getInternalURLState(this).scheme + ':';
6112 var getUsername = function () {
6113 return getInternalURLState(this).username;
6116 var getPassword = function () {
6117 return getInternalURLState(this).password;
6120 var getHost = function () {
6121 var url = getInternalURLState(this);
6122 var host = url.host;
6123 var port = url.port;
6124 return host === null ? ''
6125 : port === null ? serializeHost(host)
6126 : serializeHost(host) + ':' + port;
6129 var getHostname = function () {
6130 var host = getInternalURLState(this).host;
6131 return host === null ? '' : serializeHost(host);
6134 var getPort = function () {
6135 var port = getInternalURLState(this).port;
6136 return port === null ? '' : String(port);
6139 var getPathname = function () {
6140 var url = getInternalURLState(this);
6141 var path = url.path;
6142 return url.cannotBeABaseURL ? path[0] : path.length ? '/' + path.join('/') : '';
6145 var getSearch = function () {
6146 var query = getInternalURLState(this).query;
6147 return query ? '?' + query : '';
6150 var getSearchParams = function () {
6151 return getInternalURLState(this).searchParams;
6154 var getHash = function () {
6155 var fragment = getInternalURLState(this).fragment;
6156 return fragment ? '#' + fragment : '';
6159 var accessorDescriptor = function (getter, setter) {
6160 return { get: getter, set: setter, configurable: true, enumerable: true };
6163 if (DESCRIPTORS$a) {
6164 defineProperties$1(URLPrototype, {
6165 // `URL.prototype.href` accessors pair
6166 // https://url.spec.whatwg.org/#dom-url-href
6167 href: accessorDescriptor(serializeURL, function (href) {
6168 var url = getInternalURLState(this);
6169 var urlString = String(href);
6170 var failure = parseURL(url, urlString);
6171 if (failure) throw TypeError(failure);
6172 getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6174 // `URL.prototype.origin` getter
6175 // https://url.spec.whatwg.org/#dom-url-origin
6176 origin: accessorDescriptor(getOrigin),
6177 // `URL.prototype.protocol` accessors pair
6178 // https://url.spec.whatwg.org/#dom-url-protocol
6179 protocol: accessorDescriptor(getProtocol, function (protocol) {
6180 var url = getInternalURLState(this);
6181 parseURL(url, String(protocol) + ':', SCHEME_START);
6183 // `URL.prototype.username` accessors pair
6184 // https://url.spec.whatwg.org/#dom-url-username
6185 username: accessorDescriptor(getUsername, function (username) {
6186 var url = getInternalURLState(this);
6187 var codePoints = arrayFrom(String(username));
6188 if (cannotHaveUsernamePasswordPort(url)) return;
6190 for (var i = 0; i < codePoints.length; i++) {
6191 url.username += percentEncode(codePoints[i], userinfoPercentEncodeSet);
6194 // `URL.prototype.password` accessors pair
6195 // https://url.spec.whatwg.org/#dom-url-password
6196 password: accessorDescriptor(getPassword, function (password) {
6197 var url = getInternalURLState(this);
6198 var codePoints = arrayFrom(String(password));
6199 if (cannotHaveUsernamePasswordPort(url)) return;
6201 for (var i = 0; i < codePoints.length; i++) {
6202 url.password += percentEncode(codePoints[i], userinfoPercentEncodeSet);
6205 // `URL.prototype.host` accessors pair
6206 // https://url.spec.whatwg.org/#dom-url-host
6207 host: accessorDescriptor(getHost, function (host) {
6208 var url = getInternalURLState(this);
6209 if (url.cannotBeABaseURL) return;
6210 parseURL(url, String(host), HOST);
6212 // `URL.prototype.hostname` accessors pair
6213 // https://url.spec.whatwg.org/#dom-url-hostname
6214 hostname: accessorDescriptor(getHostname, function (hostname) {
6215 var url = getInternalURLState(this);
6216 if (url.cannotBeABaseURL) return;
6217 parseURL(url, String(hostname), HOSTNAME);
6219 // `URL.prototype.port` accessors pair
6220 // https://url.spec.whatwg.org/#dom-url-port
6221 port: accessorDescriptor(getPort, function (port) {
6222 var url = getInternalURLState(this);
6223 if (cannotHaveUsernamePasswordPort(url)) return;
6224 port = String(port);
6225 if (port == '') url.port = null;
6226 else parseURL(url, port, PORT);
6228 // `URL.prototype.pathname` accessors pair
6229 // https://url.spec.whatwg.org/#dom-url-pathname
6230 pathname: accessorDescriptor(getPathname, function (pathname) {
6231 var url = getInternalURLState(this);
6232 if (url.cannotBeABaseURL) return;
6234 parseURL(url, pathname + '', PATH_START);
6236 // `URL.prototype.search` accessors pair
6237 // https://url.spec.whatwg.org/#dom-url-search
6238 search: accessorDescriptor(getSearch, function (search) {
6239 var url = getInternalURLState(this);
6240 search = String(search);
6244 if ('?' == search.charAt(0)) search = search.slice(1);
6246 parseURL(url, search, QUERY);
6248 getInternalSearchParamsState(url.searchParams).updateSearchParams(url.query);
6250 // `URL.prototype.searchParams` getter
6251 // https://url.spec.whatwg.org/#dom-url-searchparams
6252 searchParams: accessorDescriptor(getSearchParams),
6253 // `URL.prototype.hash` accessors pair
6254 // https://url.spec.whatwg.org/#dom-url-hash
6255 hash: accessorDescriptor(getHash, function (hash) {
6256 var url = getInternalURLState(this);
6257 hash = String(hash);
6259 url.fragment = null;
6262 if ('#' == hash.charAt(0)) hash = hash.slice(1);
6264 parseURL(url, hash, FRAGMENT);
6269 // `URL.prototype.toJSON` method
6270 // https://url.spec.whatwg.org/#dom-url-tojson
6271 redefine$6(URLPrototype, 'toJSON', function toJSON() {
6272 return serializeURL.call(this);
6273 }, { enumerable: true });
6275 // `URL.prototype.toString` method
6276 // https://url.spec.whatwg.org/#URL-stringification-behavior
6277 redefine$6(URLPrototype, 'toString', function toString() {
6278 return serializeURL.call(this);
6279 }, { enumerable: true });
6282 var nativeCreateObjectURL = NativeURL.createObjectURL;
6283 var nativeRevokeObjectURL = NativeURL.revokeObjectURL;
6284 // `URL.createObjectURL` method
6285 // https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL
6286 // eslint-disable-next-line no-unused-vars -- required for `.length`
6287 if (nativeCreateObjectURL) redefine$6(URLConstructor, 'createObjectURL', function createObjectURL(blob) {
6288 return nativeCreateObjectURL.apply(NativeURL, arguments);
6290 // `URL.revokeObjectURL` method
6291 // https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL
6292 // eslint-disable-next-line no-unused-vars -- required for `.length`
6293 if (nativeRevokeObjectURL) redefine$6(URLConstructor, 'revokeObjectURL', function revokeObjectURL(url) {
6294 return nativeRevokeObjectURL.apply(NativeURL, arguments);
6298 setToStringTag$3(URLConstructor, 'URL');
6300 $$Q({ global: true, forced: !USE_NATIVE_URL, sham: !DESCRIPTORS$a }, {
6304 var anObject$7 = anObject$m;
6306 // `RegExp.prototype.flags` getter implementation
6307 // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
6308 var regexpFlags$1 = function () {
6309 var that = anObject$7(this);
6311 if (that.global) result += 'g';
6312 if (that.ignoreCase) result += 'i';
6313 if (that.multiline) result += 'm';
6314 if (that.dotAll) result += 's';
6315 if (that.unicode) result += 'u';
6316 if (that.sticky) result += 'y';
6320 var redefine$5 = redefine$g.exports;
6321 var anObject$6 = anObject$m;
6322 var fails$q = fails$N;
6323 var flags = regexpFlags$1;
6325 var TO_STRING = 'toString';
6326 var RegExpPrototype$2 = RegExp.prototype;
6327 var nativeToString = RegExpPrototype$2[TO_STRING];
6329 var NOT_GENERIC = fails$q(function () { return nativeToString.call({ source: 'a', flags: 'b' }) != '/a/b'; });
6330 // FF44- RegExp#toString has a wrong name
6331 var INCORRECT_NAME = nativeToString.name != TO_STRING;
6333 // `RegExp.prototype.toString` method
6334 // https://tc39.es/ecma262/#sec-regexp.prototype.tostring
6335 if (NOT_GENERIC || INCORRECT_NAME) {
6336 redefine$5(RegExp.prototype, TO_STRING, function toString() {
6337 var R = anObject$6(this);
6338 var p = String(R.source);
6340 var f = String(rf === undefined && R instanceof RegExp && !('flags' in RegExpPrototype$2) ? flags.call(R) : rf);
6341 return '/' + p + '/' + f;
6342 }, { unsafe: true });
6345 var regexpStickyHelpers = {};
6347 var fails$p = fails$N;
6349 // babel-minify transpiles RegExp('a', 'y') -> /a/y and it causes SyntaxError,
6350 var RE = function (s, f) {
6351 return RegExp(s, f);
6354 regexpStickyHelpers.UNSUPPORTED_Y = fails$p(function () {
6355 var re = RE('a', 'y');
6357 return re.exec('abcd') != null;
6360 regexpStickyHelpers.BROKEN_CARET = fails$p(function () {
6361 // https://bugzilla.mozilla.org/show_bug.cgi?id=773687
6362 var re = RE('^r', 'gy');
6364 return re.exec('str') != null;
6367 var fails$o = fails$N;
6369 var regexpUnsupportedDotAll = fails$o(function () {
6370 // babel-minify transpiles RegExp('.', 's') -> /./s and it causes SyntaxError
6371 var re = RegExp('.', (typeof '').charAt(0));
6372 return !(re.dotAll && re.exec('\n') && re.flags === 's');
6375 var fails$n = fails$N;
6377 var regexpUnsupportedNcg = fails$n(function () {
6378 // babel-minify transpiles RegExp('.', 'g') -> /./g and it causes SyntaxError
6379 var re = RegExp('(?<a>b)', (typeof '').charAt(5));
6380 return re.exec('b').groups.a !== 'b' ||
6381 'b'.replace(re, '$<a>c') !== 'bc';
6384 /* eslint-disable regexp/no-assertion-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */
6385 /* eslint-disable regexp/no-useless-quantifier -- testing */
6386 var regexpFlags = regexpFlags$1;
6387 var stickyHelpers$2 = regexpStickyHelpers;
6388 var shared = shared$5.exports;
6389 var create$7 = objectCreate;
6390 var getInternalState = internalState.get;
6391 var UNSUPPORTED_DOT_ALL$1 = regexpUnsupportedDotAll;
6392 var UNSUPPORTED_NCG$1 = regexpUnsupportedNcg;
6394 var nativeExec = RegExp.prototype.exec;
6395 var nativeReplace = shared('native-string-replace', String.prototype.replace);
6397 var patchedExec = nativeExec;
6399 var UPDATES_LAST_INDEX_WRONG = (function () {
6402 nativeExec.call(re1, 'a');
6403 nativeExec.call(re2, 'a');
6404 return re1.lastIndex !== 0 || re2.lastIndex !== 0;
6407 var UNSUPPORTED_Y$2 = stickyHelpers$2.UNSUPPORTED_Y || stickyHelpers$2.BROKEN_CARET;
6409 // nonparticipating capturing group, copied from es5-shim's String#split patch.
6410 var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
6412 var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y$2 || UNSUPPORTED_DOT_ALL$1 || UNSUPPORTED_NCG$1;
6415 // eslint-disable-next-line max-statements -- TODO
6416 patchedExec = function exec(str) {
6418 var state = getInternalState(re);
6419 var raw = state.raw;
6420 var result, reCopy, lastIndex, match, i, object, group;
6423 raw.lastIndex = re.lastIndex;
6424 result = patchedExec.call(raw, str);
6425 re.lastIndex = raw.lastIndex;
6429 var groups = state.groups;
6430 var sticky = UNSUPPORTED_Y$2 && re.sticky;
6431 var flags = regexpFlags.call(re);
6432 var source = re.source;
6437 flags = flags.replace('y', '');
6438 if (flags.indexOf('g') === -1) {
6442 strCopy = String(str).slice(re.lastIndex);
6443 // Support anchored sticky behavior.
6444 if (re.lastIndex > 0 && (!re.multiline || re.multiline && str[re.lastIndex - 1] !== '\n')) {
6445 source = '(?: ' + source + ')';
6446 strCopy = ' ' + strCopy;
6449 // ^(? + rx + ) is needed, in combination with some str slicing, to
6450 // simulate the 'y' flag.
6451 reCopy = new RegExp('^(?:' + source + ')', flags);
6454 if (NPCG_INCLUDED) {
6455 reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
6457 if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
6459 match = nativeExec.call(sticky ? reCopy : re, strCopy);
6463 match.input = match.input.slice(charsAdded);
6464 match[0] = match[0].slice(charsAdded);
6465 match.index = re.lastIndex;
6466 re.lastIndex += match[0].length;
6467 } else re.lastIndex = 0;
6468 } else if (UPDATES_LAST_INDEX_WRONG && match) {
6469 re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
6471 if (NPCG_INCLUDED && match && match.length > 1) {
6472 // Fix browsers whose `exec` methods don't consistently return `undefined`
6473 // for NPCG, like IE8. NOTE: This doesn' work for /(.?)?/
6474 nativeReplace.call(match[0], reCopy, function () {
6475 for (i = 1; i < arguments.length - 2; i++) {
6476 if (arguments[i] === undefined) match[i] = undefined;
6481 if (match && groups) {
6482 match.groups = object = create$7(null);
6483 for (i = 0; i < groups.length; i++) {
6485 object[group[0]] = match[group[1]];
6493 var regexpExec$3 = patchedExec;
6496 var exec = regexpExec$3;
6498 // `RegExp.prototype.exec` method
6499 // https://tc39.es/ecma262/#sec-regexp.prototype.exec
6500 $$P({ target: 'RegExp', proto: true, forced: /./.exec !== exec }, {
6504 // TODO: Remove from `core-js@4` since it's moved to entry points
6506 var redefine$4 = redefine$g.exports;
6507 var regexpExec$2 = regexpExec$3;
6508 var fails$m = fails$N;
6509 var wellKnownSymbol$5 = wellKnownSymbol$s;
6510 var createNonEnumerableProperty$1 = createNonEnumerableProperty$e;
6512 var SPECIES = wellKnownSymbol$5('species');
6513 var RegExpPrototype$1 = RegExp.prototype;
6515 var fixRegexpWellKnownSymbolLogic = function (KEY, exec, FORCED, SHAM) {
6516 var SYMBOL = wellKnownSymbol$5(KEY);
6518 var DELEGATES_TO_SYMBOL = !fails$m(function () {
6519 // String methods call symbol-named RegEp methods
6521 O[SYMBOL] = function () { return 7; };
6522 return ''[KEY](O) != 7;
6525 var DELEGATES_TO_EXEC = DELEGATES_TO_SYMBOL && !fails$m(function () {
6526 // Symbol-named RegExp methods call .exec
6527 var execCalled = false;
6530 if (KEY === 'split') {
6531 // We can't use real regex here since it causes deoptimization
6532 // and serious performance degradation in V8
6533 // https://github.com/zloirock/core-js/issues/306
6535 // RegExp[@@split] doesn't call the regex's exec method, but first creates
6536 // a new one. We need to return the patched regex when creating the new one.
6537 re.constructor = {};
6538 re.constructor[SPECIES] = function () { return re; };
6540 re[SYMBOL] = /./[SYMBOL];
6543 re.exec = function () { execCalled = true; return null; };
6550 !DELEGATES_TO_SYMBOL ||
6551 !DELEGATES_TO_EXEC ||
6554 var nativeRegExpMethod = /./[SYMBOL];
6555 var methods = exec(SYMBOL, ''[KEY], function (nativeMethod, regexp, str, arg2, forceStringMethod) {
6556 var $exec = regexp.exec;
6557 if ($exec === regexpExec$2 || $exec === RegExpPrototype$1.exec) {
6558 if (DELEGATES_TO_SYMBOL && !forceStringMethod) {
6559 // The native String method already delegates to @@method (this
6560 // polyfilled function), leasing to infinite recursion.
6561 // We avoid it by directly calling the native @@method method.
6562 return { done: true, value: nativeRegExpMethod.call(regexp, str, arg2) };
6564 return { done: true, value: nativeMethod.call(str, regexp, arg2) };
6566 return { done: false };
6569 redefine$4(String.prototype, KEY, methods[0]);
6570 redefine$4(RegExpPrototype$1, SYMBOL, methods[1]);
6573 if (SHAM) createNonEnumerableProperty$1(RegExpPrototype$1[SYMBOL], 'sham', true);
6576 var charAt = stringMultibyte.charAt;
6578 // `AdvanceStringIndex` abstract operation
6579 // https://tc39.es/ecma262/#sec-advancestringindex
6580 var advanceStringIndex$3 = function (S, index, unicode) {
6581 return index + (unicode ? charAt(S, index).length : 1);
6584 var toObject$6 = toObject$i;
6586 var floor$1 = Math.floor;
6587 var replace = ''.replace;
6588 var SUBSTITUTION_SYMBOLS = /\$([$&'`]|\d{1,2}|<[^>]*>)/g;
6589 var SUBSTITUTION_SYMBOLS_NO_NAMED = /\$([$&'`]|\d{1,2})/g;
6591 // `GetSubstitution` abstract operation
6592 // https://tc39.es/ecma262/#sec-getsubstitution
6593 var getSubstitution$1 = function (matched, str, position, captures, namedCaptures, replacement) {
6594 var tailPos = position + matched.length;
6595 var m = captures.length;
6596 var symbols = SUBSTITUTION_SYMBOLS_NO_NAMED;
6597 if (namedCaptures !== undefined) {
6598 namedCaptures = toObject$6(namedCaptures);
6599 symbols = SUBSTITUTION_SYMBOLS;
6601 return replace.call(replacement, symbols, function (match, ch) {
6603 switch (ch.charAt(0)) {
6604 case '$': return '$';
6605 case '&': return matched;
6606 case '`': return str.slice(0, position);
6607 case "'": return str.slice(tailPos);
6609 capture = namedCaptures[ch.slice(1, -1)];
6613 if (n === 0) return match;
6615 var f = floor$1(n / 10);
6616 if (f === 0) return match;
6617 if (f <= m) return captures[f - 1] === undefined ? ch.charAt(1) : captures[f - 1] + ch.charAt(1);
6620 capture = captures[n - 1];
6622 return capture === undefined ? '' : capture;
6626 var classof$3 = classofRaw$1;
6627 var regexpExec$1 = regexpExec$3;
6629 // `RegExpExec` abstract operation
6630 // https://tc39.es/ecma262/#sec-regexpexec
6631 var regexpExecAbstract = function (R, S) {
6633 if (typeof exec === 'function') {
6634 var result = exec.call(R, S);
6635 if (typeof result !== 'object') {
6636 throw TypeError('RegExp exec method returned something other than an Object or null');
6641 if (classof$3(R) !== 'RegExp') {
6642 throw TypeError('RegExp#exec called on incompatible receiver');
6645 return regexpExec$1.call(R, S);
6648 var fixRegExpWellKnownSymbolLogic$3 = fixRegexpWellKnownSymbolLogic;
6649 var fails$l = fails$N;
6650 var anObject$5 = anObject$m;
6651 var toLength$8 = toLength$q;
6652 var toInteger$3 = toInteger$b;
6653 var requireObjectCoercible$a = requireObjectCoercible$e;
6654 var advanceStringIndex$2 = advanceStringIndex$3;
6655 var getSubstitution = getSubstitution$1;
6656 var regExpExec$2 = regexpExecAbstract;
6657 var wellKnownSymbol$4 = wellKnownSymbol$s;
6659 var REPLACE = wellKnownSymbol$4('replace');
6660 var max$2 = Math.max;
6661 var min$5 = Math.min;
6663 var maybeToString = function (it) {
6664 return it === undefined ? it : String(it);
6667 // IE <= 11 replaces $0 with the whole match, as if it was $&
6668 // https://stackoverflow.com/questions/6024666/getting-ie-to-replace-a-regex-with-the-literal-string-0
6669 var REPLACE_KEEPS_$0 = (function () {
6670 // eslint-disable-next-line regexp/prefer-escape-replacement-dollar-char -- required for testing
6671 return 'a'.replace(/./, '$0') === '$0';
6674 // Safari <= 13.0.3(?) substitutes nth capture where n>m with an empty string
6675 var REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE = (function () {
6677 return /./[REPLACE]('a', '$0') === '';
6682 var REPLACE_SUPPORTS_NAMED_GROUPS = !fails$l(function () {
6684 re.exec = function () {
6686 result.groups = { a: '7' };
6689 return ''.replace(re, '$<a>') !== '7';
6693 fixRegExpWellKnownSymbolLogic$3('replace', function (_, nativeReplace, maybeCallNative) {
6694 var UNSAFE_SUBSTITUTE = REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE ? '$' : '$0';
6697 // `String.prototype.replace` method
6698 // https://tc39.es/ecma262/#sec-string.prototype.replace
6699 function replace(searchValue, replaceValue) {
6700 var O = requireObjectCoercible$a(this);
6701 var replacer = searchValue == undefined ? undefined : searchValue[REPLACE];
6702 return replacer !== undefined
6703 ? replacer.call(searchValue, O, replaceValue)
6704 : nativeReplace.call(String(O), searchValue, replaceValue);
6706 // `RegExp.prototype[@@replace]` method
6707 // https://tc39.es/ecma262/#sec-regexp.prototype-@@replace
6708 function (string, replaceValue) {
6710 typeof replaceValue === 'string' &&
6711 replaceValue.indexOf(UNSAFE_SUBSTITUTE) === -1 &&
6712 replaceValue.indexOf('$<') === -1
6714 var res = maybeCallNative(nativeReplace, this, string, replaceValue);
6715 if (res.done) return res.value;
6718 var rx = anObject$5(this);
6719 var S = String(string);
6721 var functionalReplace = typeof replaceValue === 'function';
6722 if (!functionalReplace) replaceValue = String(replaceValue);
6724 var global = rx.global;
6726 var fullUnicode = rx.unicode;
6731 var result = regExpExec$2(rx, S);
6732 if (result === null) break;
6734 results.push(result);
6737 var matchStr = String(result[0]);
6738 if (matchStr === '') rx.lastIndex = advanceStringIndex$2(S, toLength$8(rx.lastIndex), fullUnicode);
6741 var accumulatedResult = '';
6742 var nextSourcePosition = 0;
6743 for (var i = 0; i < results.length; i++) {
6744 result = results[i];
6746 var matched = String(result[0]);
6747 var position = max$2(min$5(toInteger$3(result.index), S.length), 0);
6749 // NOTE: This is equivalent to
6750 // captures = result.slice(1).map(maybeToString)
6751 // but for some reason `nativeSlice.call(result, 1, result.length)` (called in
6752 // the slice polyfill when slicing native arrays) "doesn't work" in safari 9 and
6753 // causes a crash (https://pastebin.com/N21QzeQA) when trying to debug it.
6754 for (var j = 1; j < result.length; j++) captures.push(maybeToString(result[j]));
6755 var namedCaptures = result.groups;
6756 if (functionalReplace) {
6757 var replacerArgs = [matched].concat(captures, position, S);
6758 if (namedCaptures !== undefined) replacerArgs.push(namedCaptures);
6759 var replacement = String(replaceValue.apply(undefined, replacerArgs));
6761 replacement = getSubstitution(matched, S, position, captures, namedCaptures, replaceValue);
6763 if (position >= nextSourcePosition) {
6764 accumulatedResult += S.slice(nextSourcePosition, position) + replacement;
6765 nextSourcePosition = position + matched.length;
6768 return accumulatedResult + S.slice(nextSourcePosition);
6771 }, !REPLACE_SUPPORTS_NAMED_GROUPS || !REPLACE_KEEPS_$0 || REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE);
6773 var isObject$b = isObject$r;
6774 var classof$2 = classofRaw$1;
6775 var wellKnownSymbol$3 = wellKnownSymbol$s;
6777 var MATCH$2 = wellKnownSymbol$3('match');
6779 // `IsRegExp` abstract operation
6780 // https://tc39.es/ecma262/#sec-isregexp
6781 var isRegexp = function (it) {
6783 return isObject$b(it) && ((isRegExp = it[MATCH$2]) !== undefined ? !!isRegExp : classof$2(it) == 'RegExp');
6786 var fixRegExpWellKnownSymbolLogic$2 = fixRegexpWellKnownSymbolLogic;
6787 var isRegExp$2 = isRegexp;
6788 var anObject$4 = anObject$m;
6789 var requireObjectCoercible$9 = requireObjectCoercible$e;
6790 var speciesConstructor$1 = speciesConstructor$8;
6791 var advanceStringIndex$1 = advanceStringIndex$3;
6792 var toLength$7 = toLength$q;
6793 var callRegExpExec = regexpExecAbstract;
6794 var regexpExec = regexpExec$3;
6795 var stickyHelpers$1 = regexpStickyHelpers;
6796 var fails$k = fails$N;
6798 var UNSUPPORTED_Y$1 = stickyHelpers$1.UNSUPPORTED_Y;
6799 var arrayPush = [].push;
6800 var min$4 = Math.min;
6801 var MAX_UINT32 = 0xFFFFFFFF;
6803 // Chrome 51 has a buggy "split" implementation when RegExp#exec !== nativeExec
6804 // Weex JS has frozen built-in prototypes, so use try / catch wrapper
6805 var SPLIT_WORKS_WITH_OVERWRITTEN_EXEC = !fails$k(function () {
6806 // eslint-disable-next-line regexp/no-empty-group -- required for testing
6808 var originalExec = re.exec;
6809 re.exec = function () { return originalExec.apply(this, arguments); };
6810 var result = 'ab'.split(re);
6811 return result.length !== 2 || result[0] !== 'a' || result[1] !== 'b';
6815 fixRegExpWellKnownSymbolLogic$2('split', function (SPLIT, nativeSplit, maybeCallNative) {
6818 'abbc'.split(/(b)*/)[1] == 'c' ||
6819 // eslint-disable-next-line regexp/no-empty-group -- required for testing
6820 'test'.split(/(?:)/, -1).length != 4 ||
6821 'ab'.split(/(?:ab)*/).length != 2 ||
6822 '.'.split(/(.?)(.?)/).length != 4 ||
6823 // eslint-disable-next-line regexp/no-assertion-capturing-group, regexp/no-empty-group -- required for testing
6824 '.'.split(/()()/).length > 1 ||
6825 ''.split(/.?/).length
6827 // based on es5-shim implementation, need to rework it
6828 internalSplit = function (separator, limit) {
6829 var string = String(requireObjectCoercible$9(this));
6830 var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6831 if (lim === 0) return [];
6832 if (separator === undefined) return [string];
6833 // If `separator` is not a regex, use native split
6834 if (!isRegExp$2(separator)) {
6835 return nativeSplit.call(string, separator, lim);
6838 var flags = (separator.ignoreCase ? 'i' : '') +
6839 (separator.multiline ? 'm' : '') +
6840 (separator.unicode ? 'u' : '') +
6841 (separator.sticky ? 'y' : '');
6842 var lastLastIndex = 0;
6843 // Make `global` and avoid `lastIndex` issues by working with a copy
6844 var separatorCopy = new RegExp(separator.source, flags + 'g');
6845 var match, lastIndex, lastLength;
6846 while (match = regexpExec.call(separatorCopy, string)) {
6847 lastIndex = separatorCopy.lastIndex;
6848 if (lastIndex > lastLastIndex) {
6849 output.push(string.slice(lastLastIndex, match.index));
6850 if (match.length > 1 && match.index < string.length) arrayPush.apply(output, match.slice(1));
6851 lastLength = match[0].length;
6852 lastLastIndex = lastIndex;
6853 if (output.length >= lim) break;
6855 if (separatorCopy.lastIndex === match.index) separatorCopy.lastIndex++; // Avoid an infinite loop
6857 if (lastLastIndex === string.length) {
6858 if (lastLength || !separatorCopy.test('')) output.push('');
6859 } else output.push(string.slice(lastLastIndex));
6860 return output.length > lim ? output.slice(0, lim) : output;
6863 } else if ('0'.split(undefined, 0).length) {
6864 internalSplit = function (separator, limit) {
6865 return separator === undefined && limit === 0 ? [] : nativeSplit.call(this, separator, limit);
6867 } else internalSplit = nativeSplit;
6870 // `String.prototype.split` method
6871 // https://tc39.es/ecma262/#sec-string.prototype.split
6872 function split(separator, limit) {
6873 var O = requireObjectCoercible$9(this);
6874 var splitter = separator == undefined ? undefined : separator[SPLIT];
6875 return splitter !== undefined
6876 ? splitter.call(separator, O, limit)
6877 : internalSplit.call(String(O), separator, limit);
6879 // `RegExp.prototype[@@split]` method
6880 // https://tc39.es/ecma262/#sec-regexp.prototype-@@split
6882 // NOTE: This cannot be properly polyfilled in engines that don't support
6884 function (string, limit) {
6885 var res = maybeCallNative(internalSplit, this, string, limit, internalSplit !== nativeSplit);
6886 if (res.done) return res.value;
6888 var rx = anObject$4(this);
6889 var S = String(string);
6890 var C = speciesConstructor$1(rx, RegExp);
6892 var unicodeMatching = rx.unicode;
6893 var flags = (rx.ignoreCase ? 'i' : '') +
6894 (rx.multiline ? 'm' : '') +
6895 (rx.unicode ? 'u' : '') +
6896 (UNSUPPORTED_Y$1 ? 'g' : 'y');
6898 // ^(? + rx + ) is needed, in combination with some S slicing, to
6899 // simulate the 'y' flag.
6900 var splitter = new C(UNSUPPORTED_Y$1 ? '^(?:' + rx.source + ')' : rx, flags);
6901 var lim = limit === undefined ? MAX_UINT32 : limit >>> 0;
6902 if (lim === 0) return [];
6903 if (S.length === 0) return callRegExpExec(splitter, S) === null ? [S] : [];
6907 while (q < S.length) {
6908 splitter.lastIndex = UNSUPPORTED_Y$1 ? 0 : q;
6909 var z = callRegExpExec(splitter, UNSUPPORTED_Y$1 ? S.slice(q) : S);
6913 (e = min$4(toLength$7(splitter.lastIndex + (UNSUPPORTED_Y$1 ? q : 0)), S.length)) === p
6915 q = advanceStringIndex$1(S, q, unicodeMatching);
6917 A.push(S.slice(p, q));
6918 if (A.length === lim) return A;
6919 for (var i = 1; i <= z.length - 1; i++) {
6921 if (A.length === lim) return A;
6930 }, !SPLIT_WORKS_WITH_OVERWRITTEN_EXEC, UNSUPPORTED_Y$1);
6932 // a string of all valid unicode whitespaces
6933 var whitespaces$4 = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u2000\u2001\u2002' +
6934 '\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF';
6936 var requireObjectCoercible$8 = requireObjectCoercible$e;
6937 var whitespaces$3 = whitespaces$4;
6939 var whitespace = '[' + whitespaces$3 + ']';
6940 var ltrim = RegExp('^' + whitespace + whitespace + '*');
6941 var rtrim$2 = RegExp(whitespace + whitespace + '*$');
6943 // `String.prototype.{ trim, trimStart, trimEnd, trimLeft, trimRight }` methods implementation
6944 var createMethod$2 = function (TYPE) {
6945 return function ($this) {
6946 var string = String(requireObjectCoercible$8($this));
6947 if (TYPE & 1) string = string.replace(ltrim, '');
6948 if (TYPE & 2) string = string.replace(rtrim$2, '');
6954 // `String.prototype.{ trimLeft, trimStart }` methods
6955 // https://tc39.es/ecma262/#sec-string.prototype.trimstart
6956 start: createMethod$2(1),
6957 // `String.prototype.{ trimRight, trimEnd }` methods
6958 // https://tc39.es/ecma262/#sec-string.prototype.trimend
6959 end: createMethod$2(2),
6960 // `String.prototype.trim` method
6961 // https://tc39.es/ecma262/#sec-string.prototype.trim
6962 trim: createMethod$2(3)
6965 var fails$j = fails$N;
6966 var whitespaces$2 = whitespaces$4;
6968 var non = '\u200B\u0085\u180E';
6970 // check that a method works with the correct list
6971 // of whitespaces and has a correct name
6972 var stringTrimForced = function (METHOD_NAME) {
6973 return fails$j(function () {
6974 return !!whitespaces$2[METHOD_NAME]() || non[METHOD_NAME]() != non || whitespaces$2[METHOD_NAME].name !== METHOD_NAME;
6979 var $trim = stringTrim.trim;
6980 var forcedStringTrimMethod = stringTrimForced;
6982 // `String.prototype.trim` method
6983 // https://tc39.es/ecma262/#sec-string.prototype.trim
6984 $$O({ target: 'String', proto: true, forced: forcedStringTrimMethod('trim') }, {
6985 trim: function trim() {
6990 var DESCRIPTORS$9 = descriptors;
6991 var defineProperty$4 = objectDefineProperty.f;
6993 var FunctionPrototype = Function.prototype;
6994 var FunctionPrototypeToString = FunctionPrototype.toString;
6995 var nameRE = /^\s*function ([^ (]*)/;
6998 // Function instances `.name` property
6999 // https://tc39.es/ecma262/#sec-function-instances-name
7000 if (DESCRIPTORS$9 && !(NAME in FunctionPrototype)) {
7001 defineProperty$4(FunctionPrototype, NAME, {
7005 return FunctionPrototypeToString.call(this).match(nameRE)[1];
7014 var DESCRIPTORS$8 = descriptors;
7015 var create$6 = objectCreate;
7017 // `Object.create` method
7018 // https://tc39.es/ecma262/#sec-object.create
7019 $$N({ target: 'Object', stat: true, sham: !DESCRIPTORS$8 }, {
7024 var global$9 = global$F;
7025 var userAgent = engineUserAgent;
7027 var slice$3 = [].slice;
7028 var MSIE = /MSIE .\./.test(userAgent); // <- dirty ie9- check
7030 var wrap$1 = function (scheduler) {
7031 return function (handler, timeout /* , ...arguments */) {
7032 var boundArgs = arguments.length > 2;
7033 var args = boundArgs ? slice$3.call(arguments, 2) : undefined;
7034 return scheduler(boundArgs ? function () {
7035 // eslint-disable-next-line no-new-func -- spec requirement
7036 (typeof handler == 'function' ? handler : Function(handler)).apply(this, args);
7037 } : handler, timeout);
7041 // ie9- setTimeout & setInterval additional parameters fix
7042 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers
7043 $$M({ global: true, bind: true, forced: MSIE }, {
7044 // `setTimeout` method
7045 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout
7046 setTimeout: wrap$1(global$9.setTimeout),
7047 // `setInterval` method
7048 // https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-setinterval
7049 setInterval: wrap$1(global$9.setInterval)
7052 var global$8 = typeof globalThis !== 'undefined' && globalThis || typeof self !== 'undefined' && self || typeof global$8 !== 'undefined' && global$8;
7054 searchParams: 'URLSearchParams' in global$8,
7055 iterable: 'Symbol' in global$8 && 'iterator' in Symbol,
7056 blob: 'FileReader' in global$8 && 'Blob' in global$8 && function () {
7064 formData: 'FormData' in global$8,
7065 arrayBuffer: 'ArrayBuffer' in global$8
7068 function isDataView(obj) {
7069 return obj && DataView.prototype.isPrototypeOf(obj);
7072 if (support.arrayBuffer) {
7073 var viewClasses = ['[object Int8Array]', '[object Uint8Array]', '[object Uint8ClampedArray]', '[object Int16Array]', '[object Uint16Array]', '[object Int32Array]', '[object Uint32Array]', '[object Float32Array]', '[object Float64Array]'];
7075 var isArrayBufferView = ArrayBuffer.isView || function (obj) {
7076 return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1;
7080 function normalizeName(name) {
7081 if (typeof name !== 'string') {
7082 name = String(name);
7085 if (/[^a-z0-9\-#$%&'*+.^_`|~!]/i.test(name) || name === '') {
7086 throw new TypeError('Invalid character in header field name: "' + name + '"');
7089 return name.toLowerCase();
7092 function normalizeValue(value) {
7093 if (typeof value !== 'string') {
7094 value = String(value);
7098 } // Build a destructive iterator for the value list
7101 function iteratorFor(items) {
7103 next: function next() {
7104 var value = items.shift();
7106 done: value === undefined,
7112 if (support.iterable) {
7113 iterator[Symbol.iterator] = function () {
7121 function Headers(headers) {
7124 if (headers instanceof Headers) {
7125 headers.forEach(function (value, name) {
7126 this.append(name, value);
7128 } else if (Array.isArray(headers)) {
7129 headers.forEach(function (header) {
7130 this.append(header[0], header[1]);
7132 } else if (headers) {
7133 Object.getOwnPropertyNames(headers).forEach(function (name) {
7134 this.append(name, headers[name]);
7139 Headers.prototype.append = function (name, value) {
7140 name = normalizeName(name);
7141 value = normalizeValue(value);
7142 var oldValue = this.map[name];
7143 this.map[name] = oldValue ? oldValue + ', ' + value : value;
7146 Headers.prototype['delete'] = function (name) {
7147 delete this.map[normalizeName(name)];
7150 Headers.prototype.get = function (name) {
7151 name = normalizeName(name);
7152 return this.has(name) ? this.map[name] : null;
7155 Headers.prototype.has = function (name) {
7156 return this.map.hasOwnProperty(normalizeName(name));
7159 Headers.prototype.set = function (name, value) {
7160 this.map[normalizeName(name)] = normalizeValue(value);
7163 Headers.prototype.forEach = function (callback, thisArg) {
7164 for (var name in this.map) {
7165 if (this.map.hasOwnProperty(name)) {
7166 callback.call(thisArg, this.map[name], name, this);
7171 Headers.prototype.keys = function () {
7173 this.forEach(function (value, name) {
7176 return iteratorFor(items);
7179 Headers.prototype.values = function () {
7181 this.forEach(function (value) {
7184 return iteratorFor(items);
7187 Headers.prototype.entries = function () {
7189 this.forEach(function (value, name) {
7190 items.push([name, value]);
7192 return iteratorFor(items);
7195 if (support.iterable) {
7196 Headers.prototype[Symbol.iterator] = Headers.prototype.entries;
7199 function consumed(body) {
7200 if (body.bodyUsed) {
7201 return Promise.reject(new TypeError('Already read'));
7204 body.bodyUsed = true;
7207 function fileReaderReady(reader) {
7208 return new Promise(function (resolve, reject) {
7209 reader.onload = function () {
7210 resolve(reader.result);
7213 reader.onerror = function () {
7214 reject(reader.error);
7219 function readBlobAsArrayBuffer(blob) {
7220 var reader = new FileReader();
7221 var promise = fileReaderReady(reader);
7222 reader.readAsArrayBuffer(blob);
7226 function readBlobAsText(blob) {
7227 var reader = new FileReader();
7228 var promise = fileReaderReady(reader);
7229 reader.readAsText(blob);
7233 function readArrayBufferAsText(buf) {
7234 var view = new Uint8Array(buf);
7235 var chars = new Array(view.length);
7237 for (var i = 0; i < view.length; i++) {
7238 chars[i] = String.fromCharCode(view[i]);
7241 return chars.join('');
7244 function bufferClone(buf) {
7246 return buf.slice(0);
7248 var view = new Uint8Array(buf.byteLength);
7249 view.set(new Uint8Array(buf));
7255 this.bodyUsed = false;
7257 this._initBody = function (body) {
7259 fetch-mock wraps the Response object in an ES6 Proxy to
7260 provide useful test harness features such as flush. However, on
7261 ES5 browsers without fetch or Proxy support pollyfills must be used;
7262 the proxy-pollyfill is unable to proxy an attribute unless it exists
7263 on the object before the Proxy is created. This change ensures
7264 Response.bodyUsed exists on the instance, while maintaining the
7265 semantic of setting Request.bodyUsed in the constructor before
7266 _initBody is called.
7268 this.bodyUsed = this.bodyUsed;
7269 this._bodyInit = body;
7272 this._bodyText = '';
7273 } else if (typeof body === 'string') {
7274 this._bodyText = body;
7275 } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
7276 this._bodyBlob = body;
7277 } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
7278 this._bodyFormData = body;
7279 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
7280 this._bodyText = body.toString();
7281 } else if (support.arrayBuffer && support.blob && isDataView(body)) {
7282 this._bodyArrayBuffer = bufferClone(body.buffer); // IE 10-11 can't handle a DataView body.
7284 this._bodyInit = new Blob([this._bodyArrayBuffer]);
7285 } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
7286 this._bodyArrayBuffer = bufferClone(body);
7288 this._bodyText = body = Object.prototype.toString.call(body);
7291 if (!this.headers.get('content-type')) {
7292 if (typeof body === 'string') {
7293 this.headers.set('content-type', 'text/plain;charset=UTF-8');
7294 } else if (this._bodyBlob && this._bodyBlob.type) {
7295 this.headers.set('content-type', this._bodyBlob.type);
7296 } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
7297 this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8');
7303 this.blob = function () {
7304 var rejected = consumed(this);
7310 if (this._bodyBlob) {
7311 return Promise.resolve(this._bodyBlob);
7312 } else if (this._bodyArrayBuffer) {
7313 return Promise.resolve(new Blob([this._bodyArrayBuffer]));
7314 } else if (this._bodyFormData) {
7315 throw new Error('could not read FormData body as blob');
7317 return Promise.resolve(new Blob([this._bodyText]));
7321 this.arrayBuffer = function () {
7322 if (this._bodyArrayBuffer) {
7323 var isConsumed = consumed(this);
7329 if (ArrayBuffer.isView(this._bodyArrayBuffer)) {
7330 return Promise.resolve(this._bodyArrayBuffer.buffer.slice(this._bodyArrayBuffer.byteOffset, this._bodyArrayBuffer.byteOffset + this._bodyArrayBuffer.byteLength));
7332 return Promise.resolve(this._bodyArrayBuffer);
7335 return this.blob().then(readBlobAsArrayBuffer);
7340 this.text = function () {
7341 var rejected = consumed(this);
7347 if (this._bodyBlob) {
7348 return readBlobAsText(this._bodyBlob);
7349 } else if (this._bodyArrayBuffer) {
7350 return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer));
7351 } else if (this._bodyFormData) {
7352 throw new Error('could not read FormData body as text');
7354 return Promise.resolve(this._bodyText);
7358 if (support.formData) {
7359 this.formData = function () {
7360 return this.text().then(decode);
7364 this.json = function () {
7365 return this.text().then(JSON.parse);
7369 } // HTTP methods whose capitalization should be normalized
7372 var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'];
7374 function normalizeMethod(method) {
7375 var upcased = method.toUpperCase();
7376 return methods.indexOf(upcased) > -1 ? upcased : method;
7379 function Request(input, options) {
7380 if (!(this instanceof Request)) {
7381 throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
7384 options = options || {};
7385 var body = options.body;
7387 if (input instanceof Request) {
7388 if (input.bodyUsed) {
7389 throw new TypeError('Already read');
7392 this.url = input.url;
7393 this.credentials = input.credentials;
7395 if (!options.headers) {
7396 this.headers = new Headers(input.headers);
7399 this.method = input.method;
7400 this.mode = input.mode;
7401 this.signal = input.signal;
7403 if (!body && input._bodyInit != null) {
7404 body = input._bodyInit;
7405 input.bodyUsed = true;
7408 this.url = String(input);
7411 this.credentials = options.credentials || this.credentials || 'same-origin';
7413 if (options.headers || !this.headers) {
7414 this.headers = new Headers(options.headers);
7417 this.method = normalizeMethod(options.method || this.method || 'GET');
7418 this.mode = options.mode || this.mode || null;
7419 this.signal = options.signal || this.signal;
7420 this.referrer = null;
7422 if ((this.method === 'GET' || this.method === 'HEAD') && body) {
7423 throw new TypeError('Body not allowed for GET or HEAD requests');
7426 this._initBody(body);
7428 if (this.method === 'GET' || this.method === 'HEAD') {
7429 if (options.cache === 'no-store' || options.cache === 'no-cache') {
7430 // Search for a '_' parameter in the query string
7431 var reParamSearch = /([?&])_=[^&]*/;
7433 if (reParamSearch.test(this.url)) {
7434 // If it already exists then set the value with the current time
7435 this.url = this.url.replace(reParamSearch, '$1_=' + new Date().getTime());
7437 // Otherwise add a new '_' parameter to the end with the current time
7438 var reQueryString = /\?/;
7439 this.url += (reQueryString.test(this.url) ? '&' : '?') + '_=' + new Date().getTime();
7445 Request.prototype.clone = function () {
7446 return new Request(this, {
7447 body: this._bodyInit
7451 function decode(body) {
7452 var form = new FormData();
7453 body.trim().split('&').forEach(function (bytes) {
7455 var split = bytes.split('=');
7456 var name = split.shift().replace(/\+/g, ' ');
7457 var value = split.join('=').replace(/\+/g, ' ');
7458 form.append(decodeURIComponent(name), decodeURIComponent(value));
7464 function parseHeaders(rawHeaders) {
7465 var headers = new Headers(); // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
7466 // https://tools.ietf.org/html/rfc7230#section-3.2
7468 var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' '); // Avoiding split via regex to work around a common IE11 bug with the core-js 3.6.0 regex polyfill
7469 // https://github.com/github/fetch/issues/748
7470 // https://github.com/zloirock/core-js/issues/751
7472 preProcessedHeaders.split('\r').map(function (header) {
7473 return header.indexOf('\n') === 0 ? header.substr(1, header.length) : header;
7474 }).forEach(function (line) {
7475 var parts = line.split(':');
7476 var key = parts.shift().trim();
7479 var value = parts.join(':').trim();
7480 headers.append(key, value);
7486 Body.call(Request.prototype);
7487 function Response(bodyInit, options) {
7488 if (!(this instanceof Response)) {
7489 throw new TypeError('Please use the "new" operator, this DOM object constructor cannot be called as a function.');
7496 this.type = 'default';
7497 this.status = options.status === undefined ? 200 : options.status;
7498 this.ok = this.status >= 200 && this.status < 300;
7499 this.statusText = options.statusText === undefined ? '' : '' + options.statusText;
7500 this.headers = new Headers(options.headers);
7501 this.url = options.url || '';
7503 this._initBody(bodyInit);
7505 Body.call(Response.prototype);
7507 Response.prototype.clone = function () {
7508 return new Response(this._bodyInit, {
7509 status: this.status,
7510 statusText: this.statusText,
7511 headers: new Headers(this.headers),
7516 Response.error = function () {
7517 var response = new Response(null, {
7521 response.type = 'error';
7525 var redirectStatuses = [301, 302, 303, 307, 308];
7527 Response.redirect = function (url, status) {
7528 if (redirectStatuses.indexOf(status) === -1) {
7529 throw new RangeError('Invalid status code');
7532 return new Response(null, {
7540 var DOMException$1 = global$8.DOMException;
7543 new DOMException$1();
7545 DOMException$1 = function DOMException(message, name) {
7546 this.message = message;
7548 var error = Error(message);
7549 this.stack = error.stack;
7552 DOMException$1.prototype = Object.create(Error.prototype);
7553 DOMException$1.prototype.constructor = DOMException$1;
7556 function fetch$1(input, init) {
7557 return new Promise(function (resolve, reject) {
7558 var request = new Request(input, init);
7560 if (request.signal && request.signal.aborted) {
7561 return reject(new DOMException$1('Aborted', 'AbortError'));
7564 var xhr = new XMLHttpRequest();
7566 function abortXhr() {
7570 xhr.onload = function () {
7573 statusText: xhr.statusText,
7574 headers: parseHeaders(xhr.getAllResponseHeaders() || '')
7576 options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL');
7577 var body = 'response' in xhr ? xhr.response : xhr.responseText;
7578 setTimeout(function () {
7579 resolve(new Response(body, options));
7583 xhr.onerror = function () {
7584 setTimeout(function () {
7585 reject(new TypeError('Network request failed'));
7589 xhr.ontimeout = function () {
7590 setTimeout(function () {
7591 reject(new TypeError('Network request failed'));
7595 xhr.onabort = function () {
7596 setTimeout(function () {
7597 reject(new DOMException$1('Aborted', 'AbortError'));
7601 function fixUrl(url) {
7603 return url === '' && global$8.location.href ? global$8.location.href : url;
7609 xhr.open(request.method, fixUrl(request.url), true);
7611 if (request.credentials === 'include') {
7612 xhr.withCredentials = true;
7613 } else if (request.credentials === 'omit') {
7614 xhr.withCredentials = false;
7617 if ('responseType' in xhr) {
7619 xhr.responseType = 'blob';
7620 } else if (support.arrayBuffer && request.headers.get('Content-Type') && request.headers.get('Content-Type').indexOf('application/octet-stream') !== -1) {
7621 xhr.responseType = 'arraybuffer';
7625 if (init && _typeof(init.headers) === 'object' && !(init.headers instanceof Headers)) {
7626 Object.getOwnPropertyNames(init.headers).forEach(function (name) {
7627 xhr.setRequestHeader(name, normalizeValue(init.headers[name]));
7630 request.headers.forEach(function (value, name) {
7631 xhr.setRequestHeader(name, value);
7635 if (request.signal) {
7636 request.signal.addEventListener('abort', abortXhr);
7638 xhr.onreadystatechange = function () {
7639 // DONE (success or failure)
7640 if (xhr.readyState === 4) {
7641 request.signal.removeEventListener('abort', abortXhr);
7646 xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit);
7649 fetch$1.polyfill = true;
7651 if (!global$8.fetch) {
7652 global$8.fetch = fetch$1;
7653 global$8.Headers = Headers;
7654 global$8.Request = Request;
7655 global$8.Response = Response;
7659 var DESCRIPTORS$7 = descriptors;
7660 var objectDefinePropertyModile = objectDefineProperty;
7662 // `Object.defineProperty` method
7663 // https://tc39.es/ecma262/#sec-object.defineproperty
7664 $$L({ target: 'Object', stat: true, forced: !DESCRIPTORS$7, sham: !DESCRIPTORS$7 }, {
7665 defineProperty: objectDefinePropertyModile.f
7669 var setPrototypeOf = objectSetPrototypeOf;
7671 // `Object.setPrototypeOf` method
7672 // https://tc39.es/ecma262/#sec-object.setprototypeof
7673 $$K({ target: 'Object', stat: true }, {
7674 setPrototypeOf: setPrototypeOf
7678 var fails$i = fails$N;
7679 var toObject$5 = toObject$i;
7680 var nativeGetPrototypeOf = objectGetPrototypeOf;
7681 var CORRECT_PROTOTYPE_GETTER = correctPrototypeGetter;
7683 var FAILS_ON_PRIMITIVES$3 = fails$i(function () { nativeGetPrototypeOf(1); });
7685 // `Object.getPrototypeOf` method
7686 // https://tc39.es/ecma262/#sec-object.getprototypeof
7687 $$J({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$3, sham: !CORRECT_PROTOTYPE_GETTER }, {
7688 getPrototypeOf: function getPrototypeOf(it) {
7689 return nativeGetPrototypeOf(toObject$5(it));
7693 var aFunction$2 = aFunction$9;
7694 var isObject$a = isObject$r;
7696 var slice$2 = [].slice;
7699 var construct = function (C, argsLength, args) {
7700 if (!(argsLength in factories)) {
7701 for (var list = [], i = 0; i < argsLength; i++) list[i] = 'a[' + i + ']';
7702 // eslint-disable-next-line no-new-func -- we have no proper alternatives, IE8- only
7703 factories[argsLength] = Function('C,a', 'return new C(' + list.join(',') + ')');
7704 } return factories[argsLength](C, args);
7707 // `Function.prototype.bind` method implementation
7708 // https://tc39.es/ecma262/#sec-function.prototype.bind
7709 var functionBind = Function.bind || function bind(that /* , ...args */) {
7710 var fn = aFunction$2(this);
7711 var partArgs = slice$2.call(arguments, 1);
7712 var boundFunction = function bound(/* args... */) {
7713 var args = partArgs.concat(slice$2.call(arguments));
7714 return this instanceof boundFunction ? construct(fn, args.length, args) : fn.apply(that, args);
7716 if (isObject$a(fn.prototype)) boundFunction.prototype = fn.prototype;
7717 return boundFunction;
7721 var getBuiltIn$1 = getBuiltIn$9;
7722 var aFunction$1 = aFunction$9;
7723 var anObject$3 = anObject$m;
7724 var isObject$9 = isObject$r;
7725 var create$5 = objectCreate;
7726 var bind$4 = functionBind;
7727 var fails$h = fails$N;
7729 var nativeConstruct = getBuiltIn$1('Reflect', 'construct');
7731 // `Reflect.construct` method
7732 // https://tc39.es/ecma262/#sec-reflect.construct
7733 // MS Edge supports only 2 arguments and argumentsList argument is optional
7734 // FF Nightly sets third argument as `new.target`, but does not create `this` from it
7735 var NEW_TARGET_BUG = fails$h(function () {
7736 function F() { /* empty */ }
7737 return !(nativeConstruct(function () { /* empty */ }, [], F) instanceof F);
7739 var ARGS_BUG = !fails$h(function () {
7740 nativeConstruct(function () { /* empty */ });
7742 var FORCED$a = NEW_TARGET_BUG || ARGS_BUG;
7744 $$I({ target: 'Reflect', stat: true, forced: FORCED$a, sham: FORCED$a }, {
7745 construct: function construct(Target, args /* , newTarget */) {
7746 aFunction$1(Target);
7748 var newTarget = arguments.length < 3 ? Target : aFunction$1(arguments[2]);
7749 if (ARGS_BUG && !NEW_TARGET_BUG) return nativeConstruct(Target, args, newTarget);
7750 if (Target == newTarget) {
7751 // w/o altered newTarget, optimization for 0-4 arguments
7752 switch (args.length) {
7753 case 0: return new Target();
7754 case 1: return new Target(args[0]);
7755 case 2: return new Target(args[0], args[1]);
7756 case 3: return new Target(args[0], args[1], args[2]);
7757 case 4: return new Target(args[0], args[1], args[2], args[3]);
7759 // w/o altered newTarget, lot of arguments case
7761 $args.push.apply($args, args);
7762 return new (bind$4.apply(Target, $args))();
7764 // with altered newTarget, not support built-in constructors
7765 var proto = newTarget.prototype;
7766 var instance = create$5(isObject$9(proto) ? proto : Object.prototype);
7767 var result = Function.apply.call(Target, instance, args);
7768 return isObject$9(result) ? result : instance;
7773 var isObject$8 = isObject$r;
7774 var anObject$2 = anObject$m;
7776 var getOwnPropertyDescriptorModule = objectGetOwnPropertyDescriptor;
7777 var getPrototypeOf = objectGetPrototypeOf;
7779 // `Reflect.get` method
7780 // https://tc39.es/ecma262/#sec-reflect.get
7781 function get$3(target, propertyKey /* , receiver */) {
7782 var receiver = arguments.length < 3 ? target : arguments[2];
7783 var descriptor, prototype;
7784 if (anObject$2(target) === receiver) return target[propertyKey];
7785 if (descriptor = getOwnPropertyDescriptorModule.f(target, propertyKey)) return has$3(descriptor, 'value')
7787 : descriptor.get === undefined
7789 : descriptor.get.call(receiver);
7790 if (isObject$8(prototype = getPrototypeOf(target))) return get$3(prototype, propertyKey, receiver);
7793 $$H({ target: 'Reflect', stat: true }, {
7798 var fails$g = fails$N;
7799 var toIndexedObject$1 = toIndexedObject$b;
7800 var nativeGetOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
7801 var DESCRIPTORS$6 = descriptors;
7803 var FAILS_ON_PRIMITIVES$2 = fails$g(function () { nativeGetOwnPropertyDescriptor(1); });
7804 var FORCED$9 = !DESCRIPTORS$6 || FAILS_ON_PRIMITIVES$2;
7806 // `Object.getOwnPropertyDescriptor` method
7807 // https://tc39.es/ecma262/#sec-object.getownpropertydescriptor
7808 $$G({ target: 'Object', stat: true, forced: FORCED$9, sham: !DESCRIPTORS$6 }, {
7809 getOwnPropertyDescriptor: function getOwnPropertyDescriptor(it, key) {
7810 return nativeGetOwnPropertyDescriptor(toIndexedObject$1(it), key);
7815 var toAbsoluteIndex$1 = toAbsoluteIndex$8;
7816 var toInteger$2 = toInteger$b;
7817 var toLength$6 = toLength$q;
7818 var toObject$4 = toObject$i;
7819 var arraySpeciesCreate$1 = arraySpeciesCreate$3;
7820 var createProperty$1 = createProperty$4;
7821 var arrayMethodHasSpeciesSupport$2 = arrayMethodHasSpeciesSupport$5;
7823 var HAS_SPECIES_SUPPORT$1 = arrayMethodHasSpeciesSupport$2('splice');
7825 var max$1 = Math.max;
7826 var min$3 = Math.min;
7827 var MAX_SAFE_INTEGER$1 = 0x1FFFFFFFFFFFFF;
7828 var MAXIMUM_ALLOWED_LENGTH_EXCEEDED = 'Maximum allowed length exceeded';
7830 // `Array.prototype.splice` method
7831 // https://tc39.es/ecma262/#sec-array.prototype.splice
7832 // with adding support of @@species
7833 $$F({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT$1 }, {
7834 splice: function splice(start, deleteCount /* , ...items */) {
7835 var O = toObject$4(this);
7836 var len = toLength$6(O.length);
7837 var actualStart = toAbsoluteIndex$1(start, len);
7838 var argumentsLength = arguments.length;
7839 var insertCount, actualDeleteCount, A, k, from, to;
7840 if (argumentsLength === 0) {
7841 insertCount = actualDeleteCount = 0;
7842 } else if (argumentsLength === 1) {
7844 actualDeleteCount = len - actualStart;
7846 insertCount = argumentsLength - 2;
7847 actualDeleteCount = min$3(max$1(toInteger$2(deleteCount), 0), len - actualStart);
7849 if (len + insertCount - actualDeleteCount > MAX_SAFE_INTEGER$1) {
7850 throw TypeError(MAXIMUM_ALLOWED_LENGTH_EXCEEDED);
7852 A = arraySpeciesCreate$1(O, actualDeleteCount);
7853 for (k = 0; k < actualDeleteCount; k++) {
7854 from = actualStart + k;
7855 if (from in O) createProperty$1(A, k, O[from]);
7857 A.length = actualDeleteCount;
7858 if (insertCount < actualDeleteCount) {
7859 for (k = actualStart; k < len - actualDeleteCount; k++) {
7860 from = k + actualDeleteCount;
7861 to = k + insertCount;
7862 if (from in O) O[to] = O[from];
7865 for (k = len; k > len - actualDeleteCount + insertCount; k--) delete O[k - 1];
7866 } else if (insertCount > actualDeleteCount) {
7867 for (k = len - actualDeleteCount; k > actualStart; k--) {
7868 from = k + actualDeleteCount - 1;
7869 to = k + insertCount - 1;
7870 if (from in O) O[to] = O[from];
7874 for (k = 0; k < insertCount; k++) {
7875 O[k + actualStart] = arguments[k + 2];
7877 O.length = len - actualDeleteCount + insertCount;
7882 var defineWellKnownSymbol$1 = defineWellKnownSymbol$4;
7884 // `Symbol.toStringTag` well-known symbol
7885 // https://tc39.es/ecma262/#sec-symbol.tostringtag
7886 defineWellKnownSymbol$1('toStringTag');
7888 var global$7 = global$F;
7889 var setToStringTag$2 = setToStringTag$a;
7891 // JSON[@@toStringTag] property
7892 // https://tc39.es/ecma262/#sec-json-@@tostringtag
7893 setToStringTag$2(global$7.JSON, 'JSON', true);
7895 var setToStringTag$1 = setToStringTag$a;
7897 // Math[@@toStringTag] property
7898 // https://tc39.es/ecma262/#sec-math-@@tostringtag
7899 setToStringTag$1(Math, 'Math', true);
7901 (function (factory) {
7905 function _classCallCheck(instance, Constructor) {
7906 if (!(instance instanceof Constructor)) {
7907 throw new TypeError("Cannot call a class as a function");
7911 function _defineProperties(target, props) {
7912 for (var i = 0; i < props.length; i++) {
7913 var descriptor = props[i];
7914 descriptor.enumerable = descriptor.enumerable || false;
7915 descriptor.configurable = true;
7916 if ("value" in descriptor) descriptor.writable = true;
7917 Object.defineProperty(target, descriptor.key, descriptor);
7921 function _createClass(Constructor, protoProps, staticProps) {
7922 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
7923 if (staticProps) _defineProperties(Constructor, staticProps);
7927 function _inherits(subClass, superClass) {
7928 if (typeof superClass !== "function" && superClass !== null) {
7929 throw new TypeError("Super expression must either be null or a function");
7932 subClass.prototype = Object.create(superClass && superClass.prototype, {
7939 if (superClass) _setPrototypeOf(subClass, superClass);
7942 function _getPrototypeOf(o) {
7943 _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
7944 return o.__proto__ || Object.getPrototypeOf(o);
7946 return _getPrototypeOf(o);
7949 function _setPrototypeOf(o, p) {
7950 _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
7955 return _setPrototypeOf(o, p);
7958 function _isNativeReflectConstruct() {
7959 if (typeof Reflect === "undefined" || !Reflect.construct) return false;
7960 if (Reflect.construct.sham) return false;
7961 if (typeof Proxy === "function") return true;
7964 Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
7971 function _assertThisInitialized(self) {
7972 if (self === void 0) {
7973 throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
7979 function _possibleConstructorReturn(self, call) {
7980 if (call && (_typeof(call) === "object" || typeof call === "function")) {
7984 return _assertThisInitialized(self);
7987 function _createSuper(Derived) {
7988 var hasNativeReflectConstruct = _isNativeReflectConstruct();
7990 return function _createSuperInternal() {
7991 var Super = _getPrototypeOf(Derived),
7994 if (hasNativeReflectConstruct) {
7995 var NewTarget = _getPrototypeOf(this).constructor;
7997 result = Reflect.construct(Super, arguments, NewTarget);
7999 result = Super.apply(this, arguments);
8002 return _possibleConstructorReturn(this, result);
8006 function _superPropBase(object, property) {
8007 while (!Object.prototype.hasOwnProperty.call(object, property)) {
8008 object = _getPrototypeOf(object);
8009 if (object === null) break;
8015 function _get(target, property, receiver) {
8016 if (typeof Reflect !== "undefined" && Reflect.get) {
8019 _get = function _get(target, property, receiver) {
8020 var base = _superPropBase(target, property);
8023 var desc = Object.getOwnPropertyDescriptor(base, property);
8026 return desc.get.call(receiver);
8033 return _get(target, property, receiver || target);
8036 var Emitter = /*#__PURE__*/function () {
8037 function Emitter() {
8038 _classCallCheck(this, Emitter);
8040 Object.defineProperty(this, 'listeners', {
8047 _createClass(Emitter, [{
8048 key: "addEventListener",
8049 value: function addEventListener(type, callback, options) {
8050 if (!(type in this.listeners)) {
8051 this.listeners[type] = [];
8054 this.listeners[type].push({
8060 key: "removeEventListener",
8061 value: function removeEventListener(type, callback) {
8062 if (!(type in this.listeners)) {
8066 var stack = this.listeners[type];
8068 for (var i = 0, l = stack.length; i < l; i++) {
8069 if (stack[i].callback === callback) {
8076 key: "dispatchEvent",
8077 value: function dispatchEvent(event) {
8078 if (!(event.type in this.listeners)) {
8082 var stack = this.listeners[event.type];
8083 var stackToCall = stack.slice();
8085 for (var i = 0, l = stackToCall.length; i < l; i++) {
8086 var listener = stackToCall[i];
8089 listener.callback.call(this, event);
8091 Promise.resolve().then(function () {
8096 if (listener.options && listener.options.once) {
8097 this.removeEventListener(event.type, listener.callback);
8101 return !event.defaultPrevented;
8108 var AbortSignal = /*#__PURE__*/function (_Emitter) {
8109 _inherits(AbortSignal, _Emitter);
8111 var _super = _createSuper(AbortSignal);
8113 function AbortSignal() {
8116 _classCallCheck(this, AbortSignal);
8118 _this = _super.call(this); // Some versions of babel does not transpile super() correctly for IE <= 10, if the parent
8119 // constructor has failed to run, then "this.listeners" will still be undefined and then we call
8120 // the parent constructor directly instead as a workaround. For general details, see babel bug:
8121 // https://github.com/babel/babel/issues/3041
8122 // This hack was added as a fix for the issue described here:
8123 // https://github.com/Financial-Times/polyfill-library/pull/59#issuecomment-477558042
8125 if (!_this.listeners) {
8126 Emitter.call(_assertThisInitialized(_this));
8127 } // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
8128 // we want Object.keys(new AbortController().signal) to be [] for compat with the native impl
8131 Object.defineProperty(_assertThisInitialized(_this), 'aborted', {
8136 Object.defineProperty(_assertThisInitialized(_this), 'onabort', {
8144 _createClass(AbortSignal, [{
8146 value: function toString() {
8147 return '[object AbortSignal]';
8150 key: "dispatchEvent",
8151 value: function dispatchEvent(event) {
8152 if (event.type === 'abort') {
8153 this.aborted = true;
8155 if (typeof this.onabort === 'function') {
8156 this.onabort.call(this, event);
8160 _get(_getPrototypeOf(AbortSignal.prototype), "dispatchEvent", this).call(this, event);
8167 var AbortController = /*#__PURE__*/function () {
8168 function AbortController() {
8169 _classCallCheck(this, AbortController); // Compared to assignment, Object.defineProperty makes properties non-enumerable by default and
8170 // we want Object.keys(new AbortController()) to be [] for compat with the native impl
8173 Object.defineProperty(this, 'signal', {
8174 value: new AbortSignal(),
8180 _createClass(AbortController, [{
8182 value: function abort() {
8186 event = new Event('abort');
8188 if (typeof document !== 'undefined') {
8189 if (!document.createEvent) {
8190 // For Internet Explorer 8:
8191 event = document.createEventObject();
8192 event.type = 'abort';
8194 // For Internet Explorer 11:
8195 event = document.createEvent('Event');
8196 event.initEvent('abort', false, false);
8199 // Fallback where document isn't available:
8208 this.signal.dispatchEvent(event);
8212 value: function toString() {
8213 return '[object AbortController]';
8217 return AbortController;
8220 if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
8221 // These are necessary to make sure that we get correct output for:
8222 // Object.prototype.toString.call(new AbortController())
8223 AbortController.prototype[Symbol.toStringTag] = 'AbortController';
8224 AbortSignal.prototype[Symbol.toStringTag] = 'AbortSignal';
8227 function polyfillNeeded(self) {
8228 if (self.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
8229 console.log('__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL=true is set, will force install polyfill');
8231 } // Note that the "unfetch" minimal fetch polyfill defines fetch() without
8232 // defining window.Request, and this polyfill need to work on top of unfetch
8233 // so the below feature detection needs the !self.AbortController part.
8234 // The Request.prototype check is also needed because Safari versions 11.1.2
8235 // up to and including 12.1.x has a window.AbortController present but still
8236 // does NOT correctly implement abortable fetch:
8237 // https://bugs.webkit.org/show_bug.cgi?id=174980#c2
8240 return typeof self.Request === 'function' && !self.Request.prototype.hasOwnProperty('signal') || !self.AbortController;
8243 * Note: the "fetch.Request" default value is available for fetch imported from
8244 * the "node-fetch" package and not in browsers. This is OK since browsers
8245 * will be importing umd-polyfill.js from that path "self" is passed the
8246 * decorator so the default value will not be used (because browsers that define
8247 * fetch also has Request). One quirky setup where self.fetch exists but
8248 * self.Request does not is when the "unfetch" minimal fetch polyfill is used
8249 * on top of IE11; for this case the browser will try to use the fetch.Request
8250 * default value which in turn will be undefined but then then "if (Request)"
8251 * will ensure that you get a patched fetch but still no Request (as expected).
8252 * @param {fetch, Request = fetch.Request}
8253 * @returns {fetch: abortableFetch, Request: AbortableRequest}
8257 function abortableFetchDecorator(patchTargets) {
8258 if ('function' === typeof patchTargets) {
8264 var _patchTargets = patchTargets,
8265 fetch = _patchTargets.fetch,
8266 _patchTargets$Request = _patchTargets.Request,
8267 NativeRequest = _patchTargets$Request === void 0 ? fetch.Request : _patchTargets$Request,
8268 NativeAbortController = _patchTargets.AbortController,
8269 _patchTargets$__FORCE = _patchTargets.__FORCE_INSTALL_ABORTCONTROLLER_POLYFILL,
8270 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL = _patchTargets$__FORCE === void 0 ? false : _patchTargets$__FORCE;
8272 if (!polyfillNeeded({
8274 Request: NativeRequest,
8275 AbortController: NativeAbortController,
8276 __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL: __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL
8284 var Request = NativeRequest; // Note that the "unfetch" minimal fetch polyfill defines fetch() without
8285 // defining window.Request, and this polyfill need to work on top of unfetch
8286 // hence we only patch it if it's available. Also we don't patch it if signal
8287 // is already available on the Request prototype because in this case support
8288 // is present and the patching below can cause a crash since it assigns to
8289 // request.signal which is technically a read-only property. This latter error
8290 // happens when you run the main5.js node-fetch example in the repo
8291 // "abortcontroller-polyfill-examples". The exact error is:
8292 // request.signal = init.signal;
8294 // TypeError: Cannot set property signal of #<Request> which has only a getter
8296 if (Request && !Request.prototype.hasOwnProperty('signal') || __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL) {
8297 Request = function Request(input, init) {
8300 if (init && init.signal) {
8301 signal = init.signal; // Never pass init.signal to the native Request implementation when the polyfill has
8302 // been installed because if we're running on top of a browser with a
8303 // working native AbortController (i.e. the polyfill was installed due to
8304 // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
8305 // fake AbortSignal to the native fetch will trigger:
8306 // TypeError: Failed to construct 'Request': member signal is not of type AbortSignal.
8311 var request = new NativeRequest(input, init);
8314 Object.defineProperty(request, 'signal', {
8325 Request.prototype = NativeRequest.prototype;
8328 var realFetch = fetch;
8330 var abortableFetch = function abortableFetch(input, init) {
8331 var signal = Request && Request.prototype.isPrototypeOf(input) ? input.signal : init ? init.signal : undefined;
8337 abortError = new DOMException('Aborted', 'AbortError');
8339 // IE 11 does not support calling the DOMException constructor, use a
8340 // regular error object on it instead.
8341 abortError = new Error('Aborted');
8342 abortError.name = 'AbortError';
8343 } // Return early if already aborted, thus avoiding making an HTTP request
8346 if (signal.aborted) {
8347 return Promise.reject(abortError);
8348 } // Turn an event into a promise, reject it once `abort` is dispatched
8351 var cancellation = new Promise(function (_, reject) {
8352 signal.addEventListener('abort', function () {
8353 return reject(abortError);
8359 if (init && init.signal) {
8360 // Never pass .signal to the native implementation when the polyfill has
8361 // been installed because if we're running on top of a browser with a
8362 // working native AbortController (i.e. the polyfill was installed due to
8363 // __FORCE_INSTALL_ABORTCONTROLLER_POLYFILL being set), then passing our
8364 // fake AbortSignal to the native fetch will trigger:
8365 // TypeError: Failed to execute 'fetch' on 'Window': member signal is not of type AbortSignal.
8367 } // Return the fastest promise (don't need to wait for request to finish)
8370 return Promise.race([cancellation, realFetch(input, init)]);
8373 return realFetch(input, init);
8377 fetch: abortableFetch,
8383 if (!polyfillNeeded(self)) {
8388 console.warn('fetch() is not available, cannot install abortcontroller-polyfill');
8392 var _abortableFetch = abortableFetchDecorator(self),
8393 fetch = _abortableFetch.fetch,
8394 Request = _abortableFetch.Request;
8397 self.Request = Request;
8398 Object.defineProperty(self, 'AbortController', {
8402 value: AbortController
8404 Object.defineProperty(self, 'AbortSignal', {
8410 })(typeof self !== 'undefined' ? self : commonjsGlobal);
8413 function actionAddEntity(way) {
8414 return function (graph) {
8415 return graph.replace(way);
8420 var fails$f = fails$N;
8421 var isArray$1 = isArray$6;
8422 var isObject$7 = isObject$r;
8423 var toObject$3 = toObject$i;
8424 var toLength$5 = toLength$q;
8425 var createProperty = createProperty$4;
8426 var arraySpeciesCreate = arraySpeciesCreate$3;
8427 var arrayMethodHasSpeciesSupport$1 = arrayMethodHasSpeciesSupport$5;
8428 var wellKnownSymbol$2 = wellKnownSymbol$s;
8429 var V8_VERSION = engineV8Version;
8431 var IS_CONCAT_SPREADABLE = wellKnownSymbol$2('isConcatSpreadable');
8432 var MAX_SAFE_INTEGER = 0x1FFFFFFFFFFFFF;
8433 var MAXIMUM_ALLOWED_INDEX_EXCEEDED = 'Maximum allowed index exceeded';
8435 // We can't use this feature detection in V8 since it causes
8436 // deoptimization and serious performance degradation
8437 // https://github.com/zloirock/core-js/issues/679
8438 var IS_CONCAT_SPREADABLE_SUPPORT = V8_VERSION >= 51 || !fails$f(function () {
8440 array[IS_CONCAT_SPREADABLE] = false;
8441 return array.concat()[0] !== array;
8444 var SPECIES_SUPPORT = arrayMethodHasSpeciesSupport$1('concat');
8446 var isConcatSpreadable = function (O) {
8447 if (!isObject$7(O)) return false;
8448 var spreadable = O[IS_CONCAT_SPREADABLE];
8449 return spreadable !== undefined ? !!spreadable : isArray$1(O);
8452 var FORCED$8 = !IS_CONCAT_SPREADABLE_SUPPORT || !SPECIES_SUPPORT;
8454 // `Array.prototype.concat` method
8455 // https://tc39.es/ecma262/#sec-array.prototype.concat
8456 // with adding support of @@isConcatSpreadable and @@species
8457 $$E({ target: 'Array', proto: true, forced: FORCED$8 }, {
8458 // eslint-disable-next-line no-unused-vars -- required for `.length`
8459 concat: function concat(arg) {
8460 var O = toObject$3(this);
8461 var A = arraySpeciesCreate(O, 0);
8463 var i, k, length, len, E;
8464 for (i = -1, length = arguments.length; i < length; i++) {
8465 E = i === -1 ? O : arguments[i];
8466 if (isConcatSpreadable(E)) {
8467 len = toLength$5(E.length);
8468 if (n + len > MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
8469 for (k = 0; k < len; k++, n++) if (k in E) createProperty(A, n, E[k]);
8471 if (n >= MAX_SAFE_INTEGER) throw TypeError(MAXIMUM_ALLOWED_INDEX_EXCEEDED);
8472 createProperty(A, n++, E);
8481 var assign$1 = objectAssign;
8483 // `Object.assign` method
8484 // https://tc39.es/ecma262/#sec-object.assign
8485 // eslint-disable-next-line es/no-object-assign -- required for testing
8486 $$D({ target: 'Object', stat: true, forced: Object.assign !== assign$1 }, {
8491 var $filter = arrayIteration.filter;
8492 var arrayMethodHasSpeciesSupport = arrayMethodHasSpeciesSupport$5;
8494 var HAS_SPECIES_SUPPORT = arrayMethodHasSpeciesSupport('filter');
8496 // `Array.prototype.filter` method
8497 // https://tc39.es/ecma262/#sec-array.prototype.filter
8498 // with adding support of @@species
8499 $$C({ target: 'Array', proto: true, forced: !HAS_SPECIES_SUPPORT }, {
8500 filter: function filter(callbackfn /* , thisArg */) {
8501 return $filter(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
8506 var toObject$2 = toObject$i;
8507 var nativeKeys = objectKeys$4;
8508 var fails$e = fails$N;
8510 var FAILS_ON_PRIMITIVES$1 = fails$e(function () { nativeKeys(1); });
8512 // `Object.keys` method
8513 // https://tc39.es/ecma262/#sec-object.keys
8514 $$B({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES$1 }, {
8515 keys: function keys(it) {
8516 return nativeKeys(toObject$2(it));
8521 var isArray = isArray$6;
8523 var nativeReverse = [].reverse;
8524 var test$1 = [1, 2];
8526 // `Array.prototype.reverse` method
8527 // https://tc39.es/ecma262/#sec-array.prototype.reverse
8528 // fix for Safari 12.0 bug
8529 // https://bugs.webkit.org/show_bug.cgi?id=188794
8530 $$A({ target: 'Array', proto: true, forced: String(test$1) === String(test$1.reverse()) }, {
8531 reverse: function reverse() {
8532 // eslint-disable-next-line no-self-assign -- dirty hack
8533 if (isArray(this)) this.length = this.length;
8534 return nativeReverse.call(this);
8538 var global$6 = global$F;
8539 var trim$4 = stringTrim.trim;
8540 var whitespaces$1 = whitespaces$4;
8542 var $parseFloat = global$6.parseFloat;
8543 var FORCED$7 = 1 / $parseFloat(whitespaces$1 + '-0') !== -Infinity;
8545 // `parseFloat` method
8546 // https://tc39.es/ecma262/#sec-parsefloat-string
8547 var numberParseFloat = FORCED$7 ? function parseFloat(string) {
8548 var trimmedString = trim$4(String(string));
8549 var result = $parseFloat(trimmedString);
8550 return result === 0 && trimmedString.charAt(0) == '-' ? -0 : result;
8554 var parseFloatImplementation = numberParseFloat;
8556 // `parseFloat` method
8557 // https://tc39.es/ecma262/#sec-parsefloat-string
8558 $$z({ global: true, forced: parseFloat != parseFloatImplementation }, {
8559 parseFloat: parseFloatImplementation
8563 Order the nodes of a way in reverse order and reverse any direction dependent tags
8564 other than `oneway`. (We assume that correcting a backwards oneway is the primary
8565 reason for reversing a way.)
8567 In addition, numeric-valued `incline` tags are negated.
8569 The JOSM implementation was used as a guide, but transformations that were of unclear benefit
8570 or adjusted tags that don't seem to be used in practice were omitted.
8573 http://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right
8574 http://wiki.openstreetmap.org/wiki/Key:direction#Steps
8575 http://wiki.openstreetmap.org/wiki/Key:incline
8576 http://wiki.openstreetmap.org/wiki/Route#Members
8577 http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
8578 http://wiki.openstreetmap.org/wiki/Tag:highway%3Dstop
8579 http://wiki.openstreetmap.org/wiki/Key:traffic_sign#On_a_way_or_area
8581 function actionReverse(entityID, options) {
8582 var ignoreKey = /^.*(_|:)?(description|name|note|website|ref|source|comment|watch|attribution)(_|:)?/;
8583 var numeric = /^([+\-]?)(?=[\d.])/;
8584 var directionKey = /direction$/;
8585 var turn_lanes = /^turn:lanes:?/;
8586 var keyReplacements = [[/:right$/, ':left'], [/:left$/, ':right'], [/:forward$/, ':backward'], [/:backward$/, ':forward'], [/:right:/, ':left:'], [/:left:/, ':right:'], [/:forward:/, ':backward:'], [/:backward:/, ':forward:']];
8587 var valueReplacements = {
8592 forward: 'backward',
8593 backward: 'forward',
8594 forwards: 'backward',
8595 backwards: 'forward'
8597 var roleReplacements = {
8598 forward: 'backward',
8599 backward: 'forward',
8600 forwards: 'backward',
8601 backwards: 'forward'
8603 var onewayReplacements = {
8608 var compassReplacements = {
8627 function reverseKey(key) {
8628 for (var i = 0; i < keyReplacements.length; ++i) {
8629 var replacement = keyReplacements[i];
8631 if (replacement[0].test(key)) {
8632 return key.replace(replacement[0], replacement[1]);
8639 function reverseValue(key, value, includeAbsolute) {
8640 if (ignoreKey.test(key)) return value; // Turn lanes are left/right to key (not way) direction - #5674
8642 if (turn_lanes.test(key)) {
8644 } else if (key === 'incline' && numeric.test(value)) {
8645 return value.replace(numeric, function (_, sign) {
8646 return sign === '-' ? '' : '-';
8648 } else if (options && options.reverseOneway && key === 'oneway') {
8649 return onewayReplacements[value] || value;
8650 } else if (includeAbsolute && directionKey.test(key)) {
8651 if (compassReplacements[value]) return compassReplacements[value];
8652 var degrees = parseFloat(value);
8654 if (typeof degrees === 'number' && !isNaN(degrees)) {
8655 if (degrees < 180) {
8661 return degrees.toString();
8665 return valueReplacements[value] || value;
8666 } // Reverse the direction of tags attached to the nodes - #3076
8669 function reverseNodeTags(graph, nodeIDs) {
8670 for (var i = 0; i < nodeIDs.length; i++) {
8671 var node = graph.hasEntity(nodeIDs[i]);
8672 if (!node || !Object.keys(node.tags).length) continue;
8675 for (var key in node.tags) {
8676 tags[reverseKey(key)] = reverseValue(key, node.tags[key], node.id === entityID);
8679 graph = graph.replace(node.update({
8687 function reverseWay(graph, way) {
8688 var nodes = way.nodes.slice().reverse();
8692 for (var key in way.tags) {
8693 tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
8696 graph.parentRelations(way).forEach(function (relation) {
8697 relation.members.forEach(function (member, index) {
8698 if (member.id === way.id && (role = roleReplacements[member.role])) {
8699 relation = relation.updateMember({
8702 graph = graph.replace(relation);
8705 }); // Reverse any associated directions on nodes on the way and then replace
8706 // the way itself with the reversed node ids and updated way tags
8708 return reverseNodeTags(graph, nodes).replace(way.update({
8714 var action = function action(graph) {
8715 var entity = graph.entity(entityID);
8717 if (entity.type === 'way') {
8718 return reverseWay(graph, entity);
8721 return reverseNodeTags(graph, [entityID]);
8724 action.disabled = function (graph) {
8725 var entity = graph.hasEntity(entityID);
8726 if (!entity || entity.type === 'way') return false;
8728 for (var key in entity.tags) {
8729 var value = entity.tags[key];
8731 if (reverseKey(key) !== key || reverseValue(key, value, true) !== value) {
8736 return 'nondirectional_node';
8739 action.entityID = function () {
8746 function osmIsInterestingTag(key) {
8747 return key !== 'attribution' && key !== 'created_by' && key !== 'source' && key !== 'odbl' && key.indexOf('source:') !== 0 && key.indexOf('source_ref') !== 0 && // purposely exclude colon
8748 key.indexOf('tiger:') !== 0;
8750 var osmAreaKeys = {};
8751 function osmSetAreaKeys(value) {
8752 osmAreaKeys = value;
8753 } // returns an object with the tag from `tags` that implies an area geometry, if any
8755 function osmTagSuggestingArea(tags) {
8756 if (tags.area === 'yes') return {
8759 if (tags.area === 'no') return null; // `highway` and `railway` are typically linear features, but there
8760 // are a few exceptions that should be treated as areas, even in the
8761 // absence of a proper `area=yes` or `areaKeys` tag.. see #4194
8776 var returnTags = {};
8778 for (var key in tags) {
8779 if (key in osmAreaKeys && !(tags[key] in osmAreaKeys[key])) {
8780 returnTags[key] = tags[key];
8784 if (key in lineKeys && tags[key] in lineKeys[key]) {
8785 returnTags[key] = tags[key];
8791 } // Tags that indicate a node can be a standalone point
8792 // e.g. { amenity: { bar: true, parking: true, ... } ... }
8794 var osmPointTags = {};
8795 function osmSetPointTags(value) {
8796 osmPointTags = value;
8797 } // Tags that indicate a node can be part of a way
8798 // e.g. { amenity: { parking: true, ... }, highway: { stop: true ... } ... }
8800 var osmVertexTags = {};
8801 function osmSetVertexTags(value) {
8802 osmVertexTags = value;
8804 function osmNodeGeometriesForTags(nodeTags) {
8805 var geometries = {};
8807 for (var key in nodeTags) {
8808 if (osmPointTags[key] && (osmPointTags[key]['*'] || osmPointTags[key][nodeTags[key]])) {
8809 geometries.point = true;
8812 if (osmVertexTags[key] && (osmVertexTags[key]['*'] || osmVertexTags[key][nodeTags[key]])) {
8813 geometries.vertex = true;
8814 } // break early if both are already supported
8817 if (geometries.point && geometries.vertex) break;
8822 var osmOneWayTags = {
8827 'magic_carpet': true,
8842 'goods_conveyor': true,
8843 'piste:halfpipe': true
8857 'tidal_channel': true
8859 }; // solid and smooth surfaces akin to the assumed default road surface in OSM
8861 var osmPavedTags = {
8866 'concrete:lanes': true,
8867 'concrete:plates': true
8872 }; // solid, if somewhat uncommon surfaces with a high range of smoothness
8874 var osmSemipavedTags = {
8876 'cobblestone': true,
8877 'cobblestone:flattened': true,
8878 'unhewn_cobblestone': true,
8880 'paving_stones': true,
8885 var osmRightSideIsInsideTags = {
8888 'coastline': 'coastline'
8891 'retaining_wall': true,
8902 }; // "highway" tag values for pedestrian or vehicle right-of-ways that make up the routable network
8903 // (does not include `raceway`)
8905 var osmRoutableHighwayTagValues = {
8912 motorway_link: true,
8915 secondary_link: true,
8916 tertiary_link: true,
8921 living_street: true,
8930 }; // "highway" tag values that generally do not allow motor vehicles
8932 var osmPathHighwayTagValues = {
8940 }; // "railway" tag values representing existing railroad tracks (purposely does not include 'abandoned')
8942 var osmRailwayTrackTagValues = {
8953 }; // "waterway" tag values for line features representing water flow
8955 var osmFlowingWaterwayTagValues = {
8965 var global$5 = global$F;
8966 var trim$3 = stringTrim.trim;
8967 var whitespaces = whitespaces$4;
8969 var $parseInt = global$5.parseInt;
8970 var hex$2 = /^[+-]?0[Xx]/;
8971 var FORCED$6 = $parseInt(whitespaces + '08') !== 8 || $parseInt(whitespaces + '0x16') !== 22;
8973 // `parseInt` method
8974 // https://tc39.es/ecma262/#sec-parseint-string-radix
8975 var numberParseInt = FORCED$6 ? function parseInt(string, radix) {
8976 var S = trim$3(String(string));
8977 return $parseInt(S, (radix >>> 0) || (hex$2.test(S) ? 16 : 10));
8981 var parseIntImplementation = numberParseInt;
8983 // `parseInt` method
8984 // https://tc39.es/ecma262/#sec-parseint-string-radix
8985 $$y({ global: true, forced: parseInt != parseIntImplementation }, {
8986 parseInt: parseIntImplementation
8989 var internalMetadata = {exports: {}};
8991 var fails$d = fails$N;
8993 var freezing = !fails$d(function () {
8994 // eslint-disable-next-line es/no-object-isextensible, es/no-object-preventextensions -- required for testing
8995 return Object.isExtensible(Object.preventExtensions({}));
8998 var hiddenKeys = hiddenKeys$6;
8999 var isObject$6 = isObject$r;
9001 var defineProperty$3 = objectDefineProperty.f;
9003 var FREEZING$1 = freezing;
9005 var METADATA = uid('meta');
9008 // eslint-disable-next-line es/no-object-isextensible -- safe
9009 var isExtensible = Object.isExtensible || function () {
9013 var setMetadata = function (it) {
9014 defineProperty$3(it, METADATA, { value: {
9015 objectID: 'O' + ++id$1, // object ID
9016 weakData: {} // weak collections IDs
9020 var fastKey$1 = function (it, create) {
9021 // return a primitive with prefix
9022 if (!isObject$6(it)) return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
9023 if (!has$2(it, METADATA)) {
9024 // can't set metadata to uncaught frozen object
9025 if (!isExtensible(it)) return 'F';
9026 // not necessary to add metadata
9027 if (!create) return 'E';
9028 // add missing metadata
9031 } return it[METADATA].objectID;
9034 var getWeakData = function (it, create) {
9035 if (!has$2(it, METADATA)) {
9036 // can't set metadata to uncaught frozen object
9037 if (!isExtensible(it)) return true;
9038 // not necessary to add metadata
9039 if (!create) return false;
9040 // add missing metadata
9042 // return the store of weak collections IDs
9043 } return it[METADATA].weakData;
9046 // add metadata on freeze-family methods calling
9047 var onFreeze$1 = function (it) {
9048 if (FREEZING$1 && meta.REQUIRED && isExtensible(it) && !has$2(it, METADATA)) setMetadata(it);
9052 var meta = internalMetadata.exports = {
9055 getWeakData: getWeakData,
9056 onFreeze: onFreeze$1
9059 hiddenKeys[METADATA] = true;
9062 var global$4 = global$F;
9063 var isForced$2 = isForced_1;
9064 var redefine$3 = redefine$g.exports;
9065 var InternalMetadataModule = internalMetadata.exports;
9066 var iterate$1 = iterate$3;
9067 var anInstance$1 = anInstance$7;
9068 var isObject$5 = isObject$r;
9069 var fails$c = fails$N;
9070 var checkCorrectnessOfIteration$1 = checkCorrectnessOfIteration$4;
9071 var setToStringTag = setToStringTag$a;
9072 var inheritIfRequired$2 = inheritIfRequired$4;
9074 var collection$2 = function (CONSTRUCTOR_NAME, wrapper, common) {
9075 var IS_MAP = CONSTRUCTOR_NAME.indexOf('Map') !== -1;
9076 var IS_WEAK = CONSTRUCTOR_NAME.indexOf('Weak') !== -1;
9077 var ADDER = IS_MAP ? 'set' : 'add';
9078 var NativeConstructor = global$4[CONSTRUCTOR_NAME];
9079 var NativePrototype = NativeConstructor && NativeConstructor.prototype;
9080 var Constructor = NativeConstructor;
9083 var fixMethod = function (KEY) {
9084 var nativeMethod = NativePrototype[KEY];
9085 redefine$3(NativePrototype, KEY,
9086 KEY == 'add' ? function add(value) {
9087 nativeMethod.call(this, value === 0 ? 0 : value);
9089 } : KEY == 'delete' ? function (key) {
9090 return IS_WEAK && !isObject$5(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
9091 } : KEY == 'get' ? function get(key) {
9092 return IS_WEAK && !isObject$5(key) ? undefined : nativeMethod.call(this, key === 0 ? 0 : key);
9093 } : KEY == 'has' ? function has(key) {
9094 return IS_WEAK && !isObject$5(key) ? false : nativeMethod.call(this, key === 0 ? 0 : key);
9095 } : function set(key, value) {
9096 nativeMethod.call(this, key === 0 ? 0 : key, value);
9102 var REPLACE = isForced$2(
9104 typeof NativeConstructor != 'function' || !(IS_WEAK || NativePrototype.forEach && !fails$c(function () {
9105 new NativeConstructor().entries().next();
9110 // create collection constructor
9111 Constructor = common.getConstructor(wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER);
9112 InternalMetadataModule.REQUIRED = true;
9113 } else if (isForced$2(CONSTRUCTOR_NAME, true)) {
9114 var instance = new Constructor();
9115 // early implementations not supports chaining
9116 var HASNT_CHAINING = instance[ADDER](IS_WEAK ? {} : -0, 1) != instance;
9117 // V8 ~ Chromium 40- weak-collections throws on primitives, but should return false
9118 var THROWS_ON_PRIMITIVES = fails$c(function () { instance.has(1); });
9119 // most early implementations doesn't supports iterables, most modern - not close it correctly
9120 // eslint-disable-next-line no-new -- required for testing
9121 var ACCEPT_ITERABLES = checkCorrectnessOfIteration$1(function (iterable) { new NativeConstructor(iterable); });
9122 // for early implementations -0 and +0 not the same
9123 var BUGGY_ZERO = !IS_WEAK && fails$c(function () {
9124 // V8 ~ Chromium 42- fails only with 5+ elements
9125 var $instance = new NativeConstructor();
9127 while (index--) $instance[ADDER](index, index);
9128 return !$instance.has(-0);
9131 if (!ACCEPT_ITERABLES) {
9132 Constructor = wrapper(function (dummy, iterable) {
9133 anInstance$1(dummy, Constructor, CONSTRUCTOR_NAME);
9134 var that = inheritIfRequired$2(new NativeConstructor(), dummy, Constructor);
9135 if (iterable != undefined) iterate$1(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
9138 Constructor.prototype = NativePrototype;
9139 NativePrototype.constructor = Constructor;
9142 if (THROWS_ON_PRIMITIVES || BUGGY_ZERO) {
9143 fixMethod('delete');
9145 IS_MAP && fixMethod('get');
9148 if (BUGGY_ZERO || HASNT_CHAINING) fixMethod(ADDER);
9150 // weak collections should not contains .clear method
9151 if (IS_WEAK && NativePrototype.clear) delete NativePrototype.clear;
9154 exported[CONSTRUCTOR_NAME] = Constructor;
9155 $$x({ global: true, forced: Constructor != NativeConstructor }, exported);
9157 setToStringTag(Constructor, CONSTRUCTOR_NAME);
9159 if (!IS_WEAK) common.setStrong(Constructor, CONSTRUCTOR_NAME, IS_MAP);
9164 var defineProperty$2 = objectDefineProperty.f;
9165 var create$4 = objectCreate;
9166 var redefineAll = redefineAll$4;
9167 var bind$3 = functionBindContext;
9168 var anInstance = anInstance$7;
9169 var iterate = iterate$3;
9170 var defineIterator = defineIterator$3;
9171 var setSpecies$1 = setSpecies$5;
9172 var DESCRIPTORS$5 = descriptors;
9173 var fastKey = internalMetadata.exports.fastKey;
9174 var InternalStateModule = internalState;
9176 var setInternalState = InternalStateModule.set;
9177 var internalStateGetterFor = InternalStateModule.getterFor;
9179 var collectionStrong$2 = {
9180 getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) {
9181 var C = wrapper(function (that, iterable) {
9182 anInstance(that, C, CONSTRUCTOR_NAME);
9183 setInternalState(that, {
9184 type: CONSTRUCTOR_NAME,
9185 index: create$4(null),
9190 if (!DESCRIPTORS$5) that.size = 0;
9191 if (iterable != undefined) iterate(iterable, that[ADDER], { that: that, AS_ENTRIES: IS_MAP });
9194 var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME);
9196 var define = function (that, key, value) {
9197 var state = getInternalState(that);
9198 var entry = getEntry(that, key);
9199 var previous, index;
9200 // change existing entry
9202 entry.value = value;
9205 state.last = entry = {
9206 index: index = fastKey(key, true),
9209 previous: previous = state.last,
9213 if (!state.first) state.first = entry;
9214 if (previous) previous.next = entry;
9215 if (DESCRIPTORS$5) state.size++;
9218 if (index !== 'F') state.index[index] = entry;
9222 var getEntry = function (that, key) {
9223 var state = getInternalState(that);
9225 var index = fastKey(key);
9227 if (index !== 'F') return state.index[index];
9228 // frozen object case
9229 for (entry = state.first; entry; entry = entry.next) {
9230 if (entry.key == key) return entry;
9234 redefineAll(C.prototype, {
9235 // `{ Map, Set }.prototype.clear()` methods
9236 // https://tc39.es/ecma262/#sec-map.prototype.clear
9237 // https://tc39.es/ecma262/#sec-set.prototype.clear
9238 clear: function clear() {
9240 var state = getInternalState(that);
9241 var data = state.index;
9242 var entry = state.first;
9244 entry.removed = true;
9245 if (entry.previous) entry.previous = entry.previous.next = undefined;
9246 delete data[entry.index];
9249 state.first = state.last = undefined;
9250 if (DESCRIPTORS$5) state.size = 0;
9253 // `{ Map, Set }.prototype.delete(key)` methods
9254 // https://tc39.es/ecma262/#sec-map.prototype.delete
9255 // https://tc39.es/ecma262/#sec-set.prototype.delete
9256 'delete': function (key) {
9258 var state = getInternalState(that);
9259 var entry = getEntry(that, key);
9261 var next = entry.next;
9262 var prev = entry.previous;
9263 delete state.index[entry.index];
9264 entry.removed = true;
9265 if (prev) prev.next = next;
9266 if (next) next.previous = prev;
9267 if (state.first == entry) state.first = next;
9268 if (state.last == entry) state.last = prev;
9269 if (DESCRIPTORS$5) state.size--;
9273 // `{ Map, Set }.prototype.forEach(callbackfn, thisArg = undefined)` methods
9274 // https://tc39.es/ecma262/#sec-map.prototype.foreach
9275 // https://tc39.es/ecma262/#sec-set.prototype.foreach
9276 forEach: function forEach(callbackfn /* , that = undefined */) {
9277 var state = getInternalState(this);
9278 var boundFunction = bind$3(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
9280 while (entry = entry ? entry.next : state.first) {
9281 boundFunction(entry.value, entry.key, this);
9282 // revert to the last existing entry
9283 while (entry && entry.removed) entry = entry.previous;
9286 // `{ Map, Set}.prototype.has(key)` methods
9287 // https://tc39.es/ecma262/#sec-map.prototype.has
9288 // https://tc39.es/ecma262/#sec-set.prototype.has
9289 has: function has(key) {
9290 return !!getEntry(this, key);
9294 redefineAll(C.prototype, IS_MAP ? {
9295 // `Map.prototype.get(key)` method
9296 // https://tc39.es/ecma262/#sec-map.prototype.get
9297 get: function get(key) {
9298 var entry = getEntry(this, key);
9299 return entry && entry.value;
9301 // `Map.prototype.set(key, value)` method
9302 // https://tc39.es/ecma262/#sec-map.prototype.set
9303 set: function set(key, value) {
9304 return define(this, key === 0 ? 0 : key, value);
9307 // `Set.prototype.add(value)` method
9308 // https://tc39.es/ecma262/#sec-set.prototype.add
9309 add: function add(value) {
9310 return define(this, value = value === 0 ? 0 : value, value);
9313 if (DESCRIPTORS$5) defineProperty$2(C.prototype, 'size', {
9315 return getInternalState(this).size;
9320 setStrong: function (C, CONSTRUCTOR_NAME, IS_MAP) {
9321 var ITERATOR_NAME = CONSTRUCTOR_NAME + ' Iterator';
9322 var getInternalCollectionState = internalStateGetterFor(CONSTRUCTOR_NAME);
9323 var getInternalIteratorState = internalStateGetterFor(ITERATOR_NAME);
9324 // `{ Map, Set }.prototype.{ keys, values, entries, @@iterator }()` methods
9325 // https://tc39.es/ecma262/#sec-map.prototype.entries
9326 // https://tc39.es/ecma262/#sec-map.prototype.keys
9327 // https://tc39.es/ecma262/#sec-map.prototype.values
9328 // https://tc39.es/ecma262/#sec-map.prototype-@@iterator
9329 // https://tc39.es/ecma262/#sec-set.prototype.entries
9330 // https://tc39.es/ecma262/#sec-set.prototype.keys
9331 // https://tc39.es/ecma262/#sec-set.prototype.values
9332 // https://tc39.es/ecma262/#sec-set.prototype-@@iterator
9333 defineIterator(C, CONSTRUCTOR_NAME, function (iterated, kind) {
9334 setInternalState(this, {
9335 type: ITERATOR_NAME,
9337 state: getInternalCollectionState(iterated),
9342 var state = getInternalIteratorState(this);
9343 var kind = state.kind;
9344 var entry = state.last;
9345 // revert to the last existing entry
9346 while (entry && entry.removed) entry = entry.previous;
9348 if (!state.target || !(state.last = entry = entry ? entry.next : state.state.first)) {
9349 // or finish the iteration
9350 state.target = undefined;
9351 return { value: undefined, done: true };
9353 // return step by kind
9354 if (kind == 'keys') return { value: entry.key, done: false };
9355 if (kind == 'values') return { value: entry.value, done: false };
9356 return { value: [entry.key, entry.value], done: false };
9357 }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
9359 // `{ Map, Set }.prototype[@@species]` accessors
9360 // https://tc39.es/ecma262/#sec-get-map-@@species
9361 // https://tc39.es/ecma262/#sec-get-set-@@species
9362 setSpecies$1(CONSTRUCTOR_NAME);
9366 var collection$1 = collection$2;
9367 var collectionStrong$1 = collectionStrong$2;
9369 // `Set` constructor
9370 // https://tc39.es/ecma262/#sec-set-objects
9371 collection$1('Set', function (init) {
9372 return function Set() { return init(this, arguments.length ? arguments[0] : undefined); };
9373 }, collectionStrong$1);
9375 function d3_ascending (a, b) {
9376 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
9379 function d3_bisector (f) {
9383 if (f.length === 1) {
9384 delta = function delta(d, x) {
9388 compare = ascendingComparator(f);
9391 function left(a, x, lo, hi) {
9392 if (lo == null) lo = 0;
9393 if (hi == null) hi = a.length;
9396 var mid = lo + hi >>> 1;
9397 if (compare(a[mid], x) < 0) lo = mid + 1;else hi = mid;
9403 function right(a, x, lo, hi) {
9404 if (lo == null) lo = 0;
9405 if (hi == null) hi = a.length;
9408 var mid = lo + hi >>> 1;
9409 if (compare(a[mid], x) > 0) hi = mid;else lo = mid + 1;
9415 function center(a, x, lo, hi) {
9416 if (lo == null) lo = 0;
9417 if (hi == null) hi = a.length;
9418 var i = left(a, x, lo, hi - 1);
9419 return i > lo && delta(a[i - 1], x) > -delta(a[i], x) ? i - 1 : i;
9429 function ascendingComparator(f) {
9430 return function (d, x) {
9431 return d3_ascending(f(d), x);
9435 var defineWellKnownSymbol = defineWellKnownSymbol$4;
9437 // `Symbol.asyncIterator` well-known symbol
9438 // https://tc39.es/ecma262/#sec-symbol.asynciterator
9439 defineWellKnownSymbol('asyncIterator');
9441 var runtime = {exports: {}};
9443 (function (module) {
9444 var runtime = function (exports) {
9446 var Op = Object.prototype;
9447 var hasOwn = Op.hasOwnProperty;
9448 var undefined$1; // More compressible than void 0.
9450 var $Symbol = typeof Symbol === "function" ? Symbol : {};
9451 var iteratorSymbol = $Symbol.iterator || "@@iterator";
9452 var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
9453 var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
9455 function define(obj, key, value) {
9456 Object.defineProperty(obj, key, {
9466 // IE 8 has a broken Object.defineProperty that only works on DOM objects.
9469 define = function define(obj, key, value) {
9470 return obj[key] = value;
9474 function wrap(innerFn, outerFn, self, tryLocsList) {
9475 // If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
9476 var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
9477 var generator = Object.create(protoGenerator.prototype);
9478 var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next,
9479 // .throw, and .return methods.
9481 generator._invoke = makeInvokeMethod(innerFn, self, context);
9485 exports.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completion
9486 // record like context.tryEntries[i].completion. This interface could
9487 // have been (and was previously) designed to take a closure to be
9488 // invoked without arguments, but in all the cases we care about we
9489 // already have an existing method we want to call, so there's no need
9490 // to create a new function object. We can even get away with assuming
9491 // the method takes exactly one argument, since that happens to be true
9492 // in every case, so we don't have to touch the arguments object. The
9493 // only additional allocation required is the completion record, which
9494 // has a stable shape and so hopefully should be cheap to allocate.
9496 function tryCatch(fn, obj, arg) {
9500 arg: fn.call(obj, arg)
9510 var GenStateSuspendedStart = "suspendedStart";
9511 var GenStateSuspendedYield = "suspendedYield";
9512 var GenStateExecuting = "executing";
9513 var GenStateCompleted = "completed"; // Returning this object from the innerFn has the same effect as
9514 // breaking out of the dispatch switch statement.
9516 var ContinueSentinel = {}; // Dummy constructor functions that we use as the .constructor and
9517 // .constructor.prototype properties for functions that return Generator
9518 // objects. For full spec compliance, you may wish to configure your
9519 // minifier not to mangle the names of these two functions.
9521 function Generator() {}
9523 function GeneratorFunction() {}
9525 function GeneratorFunctionPrototype() {} // This is a polyfill for %IteratorPrototype% for environments that
9526 // don't natively support it.
9529 var IteratorPrototype = {};
9531 IteratorPrototype[iteratorSymbol] = function () {
9535 var getProto = Object.getPrototypeOf;
9536 var NativeIteratorPrototype = getProto && getProto(getProto(values([])));
9538 if (NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol)) {
9539 // This environment has a native %IteratorPrototype%; use it instead
9541 IteratorPrototype = NativeIteratorPrototype;
9544 var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype);
9545 GeneratorFunction.prototype = Gp.constructor = GeneratorFunctionPrototype;
9546 GeneratorFunctionPrototype.constructor = GeneratorFunction;
9547 GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"); // Helper for defining the .next, .throw, and .return methods of the
9548 // Iterator interface in terms of a single ._invoke method.
9550 function defineIteratorMethods(prototype) {
9551 ["next", "throw", "return"].forEach(function (method) {
9552 define(prototype, method, function (arg) {
9553 return this._invoke(method, arg);
9558 exports.isGeneratorFunction = function (genFun) {
9559 var ctor = typeof genFun === "function" && genFun.constructor;
9560 return ctor ? ctor === GeneratorFunction || // For the native GeneratorFunction constructor, the best we can
9561 // do is to check its .name property.
9562 (ctor.displayName || ctor.name) === "GeneratorFunction" : false;
9565 exports.mark = function (genFun) {
9566 if (Object.setPrototypeOf) {
9567 Object.setPrototypeOf(genFun, GeneratorFunctionPrototype);
9569 genFun.__proto__ = GeneratorFunctionPrototype;
9570 define(genFun, toStringTagSymbol, "GeneratorFunction");
9573 genFun.prototype = Object.create(Gp);
9575 }; // Within the body of any async function, `await x` is transformed to
9576 // `yield regeneratorRuntime.awrap(x)`, so that the runtime can test
9577 // `hasOwn.call(value, "__await")` to determine if the yielded value is
9578 // meant to be awaited.
9581 exports.awrap = function (arg) {
9587 function AsyncIterator(generator, PromiseImpl) {
9588 function invoke(method, arg, resolve, reject) {
9589 var record = tryCatch(generator[method], generator, arg);
9591 if (record.type === "throw") {
9594 var result = record.arg;
9595 var value = result.value;
9597 if (value && _typeof(value) === "object" && hasOwn.call(value, "__await")) {
9598 return PromiseImpl.resolve(value.__await).then(function (value) {
9599 invoke("next", value, resolve, reject);
9601 invoke("throw", err, resolve, reject);
9605 return PromiseImpl.resolve(value).then(function (unwrapped) {
9606 // When a yielded Promise is resolved, its final value becomes
9607 // the .value of the Promise<{value,done}> result for the
9608 // current iteration.
9609 result.value = unwrapped;
9611 }, function (error) {
9612 // If a rejected Promise was yielded, throw the rejection back
9613 // into the async generator function so it can be handled there.
9614 return invoke("throw", error, resolve, reject);
9619 var previousPromise;
9621 function enqueue(method, arg) {
9622 function callInvokeWithMethodAndArg() {
9623 return new PromiseImpl(function (resolve, reject) {
9624 invoke(method, arg, resolve, reject);
9628 return previousPromise = // If enqueue has been called before, then we want to wait until
9629 // all previous Promises have been resolved before calling invoke,
9630 // so that results are always delivered in the correct order. If
9631 // enqueue has not been called before, then it is important to
9632 // call invoke immediately, without waiting on a callback to fire,
9633 // so that the async generator function has the opportunity to do
9634 // any necessary setup in a predictable way. This predictability
9635 // is why the Promise constructor synchronously invokes its
9636 // executor callback, and why async functions synchronously
9637 // execute code before the first await. Since we implement simple
9638 // async functions in terms of async generators, it is especially
9639 // important to get this right, even though it requires care.
9640 previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, // Avoid propagating failures to Promises returned by later
9641 // invocations of the iterator.
9642 callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg();
9643 } // Define the unified helper method that is used to implement .next,
9644 // .throw, and .return (see defineIteratorMethods).
9647 this._invoke = enqueue;
9650 defineIteratorMethods(AsyncIterator.prototype);
9652 AsyncIterator.prototype[asyncIteratorSymbol] = function () {
9656 exports.AsyncIterator = AsyncIterator; // Note that simple async functions are implemented on top of
9657 // AsyncIterator objects; they just return a Promise for the value of
9658 // the final result produced by the iterator.
9660 exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) {
9661 if (PromiseImpl === void 0) PromiseImpl = Promise;
9662 var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl);
9663 return exports.isGeneratorFunction(outerFn) ? iter // If outerFn is a generator, return the full iterator.
9664 : iter.next().then(function (result) {
9665 return result.done ? result.value : iter.next();
9669 function makeInvokeMethod(innerFn, self, context) {
9670 var state = GenStateSuspendedStart;
9671 return function invoke(method, arg) {
9672 if (state === GenStateExecuting) {
9673 throw new Error("Generator is already running");
9676 if (state === GenStateCompleted) {
9677 if (method === "throw") {
9679 } // Be forgiving, per 25.3.3.3.3 of the spec:
9680 // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-generatorresume
9683 return doneResult();
9686 context.method = method;
9690 var delegate = context.delegate;
9693 var delegateResult = maybeInvokeDelegate(delegate, context);
9695 if (delegateResult) {
9696 if (delegateResult === ContinueSentinel) continue;
9697 return delegateResult;
9701 if (context.method === "next") {
9702 // Setting context._sent for legacy support of Babel's
9703 // function.sent implementation.
9704 context.sent = context._sent = context.arg;
9705 } else if (context.method === "throw") {
9706 if (state === GenStateSuspendedStart) {
9707 state = GenStateCompleted;
9711 context.dispatchException(context.arg);
9712 } else if (context.method === "return") {
9713 context.abrupt("return", context.arg);
9716 state = GenStateExecuting;
9717 var record = tryCatch(innerFn, self, context);
9719 if (record.type === "normal") {
9720 // If an exception is thrown from innerFn, we leave state ===
9721 // GenStateExecuting and loop back for another invocation.
9722 state = context.done ? GenStateCompleted : GenStateSuspendedYield;
9724 if (record.arg === ContinueSentinel) {
9732 } else if (record.type === "throw") {
9733 state = GenStateCompleted; // Dispatch the exception by looping back around to the
9734 // context.dispatchException(context.arg) call above.
9736 context.method = "throw";
9737 context.arg = record.arg;
9741 } // Call delegate.iterator[context.method](context.arg) and handle the
9742 // result, either by returning a { value, done } result from the
9743 // delegate iterator, or by modifying context.method and context.arg,
9744 // setting context.delegate to null, and returning the ContinueSentinel.
9747 function maybeInvokeDelegate(delegate, context) {
9748 var method = delegate.iterator[context.method];
9750 if (method === undefined$1) {
9751 // A .throw or .return when the delegate iterator has no .throw
9752 // method always terminates the yield* loop.
9753 context.delegate = null;
9755 if (context.method === "throw") {
9756 // Note: ["return"] must be used for ES3 parsing compatibility.
9757 if (delegate.iterator["return"]) {
9758 // If the delegate iterator has a return method, give it a
9759 // chance to clean up.
9760 context.method = "return";
9761 context.arg = undefined$1;
9762 maybeInvokeDelegate(delegate, context);
9764 if (context.method === "throw") {
9765 // If maybeInvokeDelegate(context) changed context.method from
9766 // "return" to "throw", let that override the TypeError below.
9767 return ContinueSentinel;
9771 context.method = "throw";
9772 context.arg = new TypeError("The iterator does not provide a 'throw' method");
9775 return ContinueSentinel;
9778 var record = tryCatch(method, delegate.iterator, context.arg);
9780 if (record.type === "throw") {
9781 context.method = "throw";
9782 context.arg = record.arg;
9783 context.delegate = null;
9784 return ContinueSentinel;
9787 var info = record.arg;
9790 context.method = "throw";
9791 context.arg = new TypeError("iterator result is not an object");
9792 context.delegate = null;
9793 return ContinueSentinel;
9797 // Assign the result of the finished delegate to the temporary
9798 // variable specified by delegate.resultName (see delegateYield).
9799 context[delegate.resultName] = info.value; // Resume execution at the desired location (see delegateYield).
9801 context.next = delegate.nextLoc; // If context.method was "throw" but the delegate handled the
9802 // exception, let the outer generator proceed normally. If
9803 // context.method was "next", forget context.arg since it has been
9804 // "consumed" by the delegate iterator. If context.method was
9805 // "return", allow the original .return call to continue in the
9808 if (context.method !== "return") {
9809 context.method = "next";
9810 context.arg = undefined$1;
9813 // Re-yield the result returned by the delegate method.
9815 } // The delegate iterator is finished, so forget it and continue with
9816 // the outer generator.
9819 context.delegate = null;
9820 return ContinueSentinel;
9821 } // Define Generator.prototype.{next,throw,return} in terms of the
9822 // unified ._invoke helper method.
9825 defineIteratorMethods(Gp);
9826 define(Gp, toStringTagSymbol, "Generator"); // A Generator should always return itself as the iterator object when the
9827 // @@iterator function is called on it. Some browsers' implementations of the
9828 // iterator prototype chain incorrectly implement this, causing the Generator
9829 // object to not be returned from this call. This ensures that doesn't happen.
9830 // See https://github.com/facebook/regenerator/issues/274 for more details.
9832 Gp[iteratorSymbol] = function () {
9836 Gp.toString = function () {
9837 return "[object Generator]";
9840 function pushTryEntry(locs) {
9846 entry.catchLoc = locs[1];
9850 entry.finallyLoc = locs[2];
9851 entry.afterLoc = locs[3];
9854 this.tryEntries.push(entry);
9857 function resetTryEntry(entry) {
9858 var record = entry.completion || {};
9859 record.type = "normal";
9861 entry.completion = record;
9864 function Context(tryLocsList) {
9865 // The root entry object (effectively a try statement without a catch
9866 // or a finally block) gives us a place to store values thrown from
9867 // locations where there is no enclosing try statement.
9868 this.tryEntries = [{
9871 tryLocsList.forEach(pushTryEntry, this);
9875 exports.keys = function (object) {
9878 for (var key in object) {
9882 keys.reverse(); // Rather than returning an object with a next method, we keep
9883 // things simple and return the next function itself.
9885 return function next() {
9886 while (keys.length) {
9887 var key = keys.pop();
9889 if (key in object) {
9894 } // To avoid creating an additional object, we just hang the .value
9895 // and .done properties off the next function object itself. This
9896 // also ensures that the minifier will not anonymize the function.
9904 function values(iterable) {
9906 var iteratorMethod = iterable[iteratorSymbol];
9908 if (iteratorMethod) {
9909 return iteratorMethod.call(iterable);
9912 if (typeof iterable.next === "function") {
9916 if (!isNaN(iterable.length)) {
9918 next = function next() {
9919 while (++i < iterable.length) {
9920 if (hasOwn.call(iterable, i)) {
9921 next.value = iterable[i];
9927 next.value = undefined$1;
9932 return next.next = next;
9934 } // Return an iterator with no values.
9942 exports.values = values;
9944 function doneResult() {
9951 Context.prototype = {
9952 constructor: Context,
9953 reset: function reset(skipTempReset) {
9955 this.next = 0; // Resetting context._sent for legacy support of Babel's
9956 // function.sent implementation.
9958 this.sent = this._sent = undefined$1;
9960 this.delegate = null;
9961 this.method = "next";
9962 this.arg = undefined$1;
9963 this.tryEntries.forEach(resetTryEntry);
9965 if (!skipTempReset) {
9966 for (var name in this) {
9967 // Not sure about the optimal order of these conditions:
9968 if (name.charAt(0) === "t" && hasOwn.call(this, name) && !isNaN(+name.slice(1))) {
9969 this[name] = undefined$1;
9974 stop: function stop() {
9976 var rootEntry = this.tryEntries[0];
9977 var rootRecord = rootEntry.completion;
9979 if (rootRecord.type === "throw") {
9980 throw rootRecord.arg;
9985 dispatchException: function dispatchException(exception) {
9992 function handle(loc, caught) {
9993 record.type = "throw";
9994 record.arg = exception;
9998 // If the dispatched exception was caught by a catch block,
9999 // then let that catch block handle the exception normally.
10000 context.method = "next";
10001 context.arg = undefined$1;
10007 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10008 var entry = this.tryEntries[i];
10009 var record = entry.completion;
10011 if (entry.tryLoc === "root") {
10012 // Exception thrown outside of any try block that could handle
10013 // it, so set the completion value of the entire function to
10014 // throw the exception.
10015 return handle("end");
10018 if (entry.tryLoc <= this.prev) {
10019 var hasCatch = hasOwn.call(entry, "catchLoc");
10020 var hasFinally = hasOwn.call(entry, "finallyLoc");
10022 if (hasCatch && hasFinally) {
10023 if (this.prev < entry.catchLoc) {
10024 return handle(entry.catchLoc, true);
10025 } else if (this.prev < entry.finallyLoc) {
10026 return handle(entry.finallyLoc);
10028 } else if (hasCatch) {
10029 if (this.prev < entry.catchLoc) {
10030 return handle(entry.catchLoc, true);
10032 } else if (hasFinally) {
10033 if (this.prev < entry.finallyLoc) {
10034 return handle(entry.finallyLoc);
10037 throw new Error("try statement without catch or finally");
10042 abrupt: function abrupt(type, arg) {
10043 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10044 var entry = this.tryEntries[i];
10046 if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) {
10047 var finallyEntry = entry;
10052 if (finallyEntry && (type === "break" || type === "continue") && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc) {
10053 // Ignore the finally entry if control is not jumping to a
10054 // location outside the try/catch block.
10055 finallyEntry = null;
10058 var record = finallyEntry ? finallyEntry.completion : {};
10059 record.type = type;
10062 if (finallyEntry) {
10063 this.method = "next";
10064 this.next = finallyEntry.finallyLoc;
10065 return ContinueSentinel;
10068 return this.complete(record);
10070 complete: function complete(record, afterLoc) {
10071 if (record.type === "throw") {
10075 if (record.type === "break" || record.type === "continue") {
10076 this.next = record.arg;
10077 } else if (record.type === "return") {
10078 this.rval = this.arg = record.arg;
10079 this.method = "return";
10081 } else if (record.type === "normal" && afterLoc) {
10082 this.next = afterLoc;
10085 return ContinueSentinel;
10087 finish: function finish(finallyLoc) {
10088 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10089 var entry = this.tryEntries[i];
10091 if (entry.finallyLoc === finallyLoc) {
10092 this.complete(entry.completion, entry.afterLoc);
10093 resetTryEntry(entry);
10094 return ContinueSentinel;
10098 "catch": function _catch(tryLoc) {
10099 for (var i = this.tryEntries.length - 1; i >= 0; --i) {
10100 var entry = this.tryEntries[i];
10102 if (entry.tryLoc === tryLoc) {
10103 var record = entry.completion;
10105 if (record.type === "throw") {
10106 var thrown = record.arg;
10107 resetTryEntry(entry);
10112 } // The context.catch method must only be called with a location
10113 // argument that corresponds to a known catch block.
10116 throw new Error("illegal catch attempt");
10118 delegateYield: function delegateYield(iterable, resultName, nextLoc) {
10120 iterator: values(iterable),
10121 resultName: resultName,
10125 if (this.method === "next") {
10126 // Deliberately forget the last sent value so that we don't
10127 // accidentally pass it on to the delegate.
10128 this.arg = undefined$1;
10131 return ContinueSentinel;
10133 }; // Regardless of whether this script is executing as a CommonJS module
10134 // or not, return the runtime object so that we can declare the variable
10135 // regeneratorRuntime in the outer scope, which allows this module to be
10136 // injected easily by `bin/regenerator --include-runtime script.js`.
10139 }( // If this script is executing as a CommonJS module, use module.exports
10140 // as the regeneratorRuntime namespace. Otherwise create a new empty
10141 // object. Either way, the resulting object will be used to initialize
10142 // the regeneratorRuntime variable at the top of this file.
10146 regeneratorRuntime = runtime;
10147 } catch (accidentalStrictMode) {
10148 // This module should not be running in strict mode, so the above
10149 // assignment should always work unless something is misconfigured. Just
10150 // in case runtime.js accidentally runs in strict mode, we can escape
10151 // strict mode using a global Function call. This could conceivably fail
10152 // if a Content Security Policy forbids using Function, but in that case
10153 // the proper solution is to fix the accidental strict mode problem. If
10154 // you've misconfigured your bundler to force strict mode and applied a
10155 // CSP to forbid Function, and you're not willing to fix either of those
10156 // problems, please detail your unique predicament in a GitHub issue.
10157 Function("r", "regeneratorRuntime = r")(runtime);
10161 var _marked$3 = /*#__PURE__*/regeneratorRuntime.mark(numbers);
10163 function number$1 (x) {
10164 return x === null ? NaN : +x;
10166 function numbers(values, valueof) {
10167 var _iterator, _step, value, index, _iterator2, _step2, _value;
10169 return regeneratorRuntime.wrap(function numbers$(_context) {
10171 switch (_context.prev = _context.next) {
10173 if (!(valueof === undefined)) {
10174 _context.next = 21;
10178 _iterator = _createForOfIteratorHelper(values);
10184 if ((_step = _iterator.n()).done) {
10185 _context.next = 11;
10189 value = _step.value;
10191 if (!(value != null && (value = +value) >= value)) {
10204 _context.next = 16;
10208 _context.prev = 13;
10209 _context.t0 = _context["catch"](2);
10211 _iterator.e(_context.t0);
10214 _context.prev = 16;
10218 return _context.finish(16);
10221 _context.next = 40;
10226 _iterator2 = _createForOfIteratorHelper(values);
10227 _context.prev = 23;
10232 if ((_step2 = _iterator2.n()).done) {
10233 _context.next = 32;
10237 _value = _step2.value;
10239 if (!((_value = valueof(_value, ++index, values)) != null && (_value = +_value) >= _value)) {
10240 _context.next = 30;
10244 _context.next = 30;
10248 _context.next = 25;
10252 _context.next = 37;
10256 _context.prev = 34;
10257 _context.t1 = _context["catch"](23);
10259 _iterator2.e(_context.t1);
10262 _context.prev = 37;
10266 return _context.finish(37);
10270 return _context.stop();
10273 }, _marked$3, null, [[2, 13, 16, 19], [23, 34, 37, 40]]);
10276 var ascendingBisect = d3_bisector(d3_ascending);
10277 var bisectRight = ascendingBisect.right;
10278 d3_bisector(number$1).center;
10281 var from = arrayFrom$1;
10282 var checkCorrectnessOfIteration = checkCorrectnessOfIteration$4;
10284 var INCORRECT_ITERATION = !checkCorrectnessOfIteration(function (iterable) {
10285 // eslint-disable-next-line es/no-array-from -- required for testing
10286 Array.from(iterable);
10289 // `Array.from` method
10290 // https://tc39.es/ecma262/#sec-array.from
10291 $$w({ target: 'Array', stat: true, forced: INCORRECT_ITERATION }, {
10296 var fill = arrayFill$1;
10297 var addToUnscopables$3 = addToUnscopables$5;
10299 // `Array.prototype.fill` method
10300 // https://tc39.es/ecma262/#sec-array.prototype.fill
10301 $$v({ target: 'Array', proto: true }, {
10305 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
10306 addToUnscopables$3('fill');
10309 var $some = arrayIteration.some;
10310 var arrayMethodIsStrict$3 = arrayMethodIsStrict$8;
10312 var STRICT_METHOD$3 = arrayMethodIsStrict$3('some');
10314 // `Array.prototype.some` method
10315 // https://tc39.es/ecma262/#sec-array.prototype.some
10316 $$u({ target: 'Array', proto: true, forced: !STRICT_METHOD$3 }, {
10317 some: function some(callbackfn /* , thisArg */) {
10318 return $some(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
10322 var TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS = typedArrayConstructorsRequireWrappers;
10323 var exportTypedArrayStaticMethod = arrayBufferViewCore.exportTypedArrayStaticMethod;
10324 var typedArrayFrom = typedArrayFrom$2;
10326 // `%TypedArray%.from` method
10327 // https://tc39.es/ecma262/#sec-%typedarray%.from
10328 exportTypedArrayStaticMethod('from', typedArrayFrom, TYPED_ARRAYS_CONSTRUCTORS_REQUIRES_WRAPPERS);
10330 var createTypedArrayConstructor = typedArrayConstructor.exports;
10332 // `Float64Array` constructor
10333 // https://tc39.es/ecma262/#sec-typedarray-objects
10334 createTypedArrayConstructor('Float64', function (init) {
10335 return function Float64Array(data, byteOffset, length) {
10336 return init(this, data, byteOffset, length);
10340 function d3_descending (a, b) {
10341 return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
10344 // https://github.com/python/cpython/blob/a74eea238f5baba15797e2e8b570d153bc8690a7/Modules/mathmodule.c#L1423
10345 var Adder = /*#__PURE__*/function () {
10347 _classCallCheck$1(this, Adder);
10349 this._partials = new Float64Array(32);
10353 _createClass$1(Adder, [{
10355 value: function add(x) {
10356 var p = this._partials;
10359 for (var j = 0; j < this._n && j < 32; j++) {
10362 lo = Math.abs(x) < Math.abs(y) ? x - (hi - y) : y - (hi - x);
10363 if (lo) p[i++] = lo;
10373 value: function valueOf() {
10374 var p = this._partials;
10392 if (n > 0 && (lo < 0 && p[n - 1] < 0 || lo > 0 && p[n - 1] > 0)) {
10395 if (y == x - hi) hi = x;
10407 var DESCRIPTORS$4 = descriptors;
10408 var defineProperties = objectDefineProperties;
10410 // `Object.defineProperties` method
10411 // https://tc39.es/ecma262/#sec-object.defineproperties
10412 $$t({ target: 'Object', stat: true, forced: !DESCRIPTORS$4, sham: !DESCRIPTORS$4 }, {
10413 defineProperties: defineProperties
10416 var collection = collection$2;
10417 var collectionStrong = collectionStrong$2;
10419 // `Map` constructor
10420 // https://tc39.es/ecma262/#sec-map-objects
10421 collection('Map', function (init) {
10422 return function Map() { return init(this, arguments.length ? arguments[0] : undefined); };
10423 }, collectionStrong);
10426 var aFunction = aFunction$9;
10427 var toObject$1 = toObject$i;
10428 var toLength$4 = toLength$q;
10429 var fails$b = fails$N;
10430 var internalSort = arraySort;
10431 var arrayMethodIsStrict$2 = arrayMethodIsStrict$8;
10432 var FF = engineFfVersion;
10433 var IE_OR_EDGE = engineIsIeOrEdge;
10434 var V8 = engineV8Version;
10435 var WEBKIT = engineWebkitVersion;
10438 var nativeSort = test.sort;
10441 var FAILS_ON_UNDEFINED = fails$b(function () {
10442 test.sort(undefined);
10445 var FAILS_ON_NULL = fails$b(function () {
10449 var STRICT_METHOD$2 = arrayMethodIsStrict$2('sort');
10451 var STABLE_SORT = !fails$b(function () {
10452 // feature detection can be too slow, so check engines versions
10453 if (V8) return V8 < 70;
10454 if (FF && FF > 3) return;
10455 if (IE_OR_EDGE) return true;
10456 if (WEBKIT) return WEBKIT < 603;
10459 var code, chr, value, index;
10461 // generate an array with more 512 elements (Chakra and old V8 fails only in this case)
10462 for (code = 65; code < 76; code++) {
10463 chr = String.fromCharCode(code);
10466 case 66: case 69: case 70: case 72: value = 3; break;
10467 case 68: case 71: value = 4; break;
10468 default: value = 2;
10471 for (index = 0; index < 47; index++) {
10472 test.push({ k: chr + index, v: value });
10476 test.sort(function (a, b) { return b.v - a.v; });
10478 for (index = 0; index < test.length; index++) {
10479 chr = test[index].k.charAt(0);
10480 if (result.charAt(result.length - 1) !== chr) result += chr;
10483 return result !== 'DGBEFHACIJK';
10486 var FORCED$5 = FAILS_ON_UNDEFINED || !FAILS_ON_NULL || !STRICT_METHOD$2 || !STABLE_SORT;
10488 var getSortCompare = function (comparefn) {
10489 return function (x, y) {
10490 if (y === undefined) return -1;
10491 if (x === undefined) return 1;
10492 if (comparefn !== undefined) return +comparefn(x, y) || 0;
10493 return String(x) > String(y) ? 1 : -1;
10497 // `Array.prototype.sort` method
10498 // https://tc39.es/ecma262/#sec-array.prototype.sort
10499 $$s({ target: 'Array', proto: true, forced: FORCED$5 }, {
10500 sort: function sort(comparefn) {
10501 if (comparefn !== undefined) aFunction(comparefn);
10503 var array = toObject$1(this);
10505 if (STABLE_SORT) return comparefn === undefined ? nativeSort.call(array) : nativeSort.call(array, comparefn);
10508 var arrayLength = toLength$4(array.length);
10509 var itemsLength, index;
10511 for (index = 0; index < arrayLength; index++) {
10512 if (index in array) items.push(array[index]);
10515 items = internalSort(items, getSortCompare(comparefn));
10516 itemsLength = items.length;
10519 while (index < itemsLength) array[index] = items[index++];
10520 while (index < arrayLength) delete array[index++];
10526 var e10 = Math.sqrt(50),
10527 e5 = Math.sqrt(10),
10529 function ticks (start, stop, count) {
10535 stop = +stop, start = +start, count = +count;
10536 if (start === stop && count > 0) return [start];
10537 if (reverse = stop < start) n = start, start = stop, stop = n;
10538 if ((step = tickIncrement(start, stop, count)) === 0 || !isFinite(step)) return [];
10541 var r0 = Math.round(start / step),
10542 r1 = Math.round(stop / step);
10543 if (r0 * step < start) ++r0;
10544 if (r1 * step > stop) --r1;
10545 ticks = new Array(n = r1 - r0 + 1);
10548 ticks[i] = (r0 + i) * step;
10553 var _r = Math.round(start * step),
10554 _r2 = Math.round(stop * step);
10556 if (_r / step < start) ++_r;
10557 if (_r2 / step > stop) --_r2;
10558 ticks = new Array(n = _r2 - _r + 1);
10561 ticks[i] = (_r + i) / step;
10565 if (reverse) ticks.reverse();
10568 function tickIncrement(start, stop, count) {
10569 var step = (stop - start) / Math.max(0, count),
10570 power = Math.floor(Math.log(step) / Math.LN10),
10571 error = step / Math.pow(10, power);
10572 return power >= 0 ? (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1) * Math.pow(10, power) : -Math.pow(10, -power) / (error >= e10 ? 10 : error >= e5 ? 5 : error >= e2 ? 2 : 1);
10574 function tickStep(start, stop, count) {
10575 var step0 = Math.abs(stop - start) / Math.max(0, count),
10576 step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
10577 error = step0 / step1;
10578 if (error >= e10) step1 *= 10;else if (error >= e5) step1 *= 5;else if (error >= e2) step1 *= 2;
10579 return stop < start ? -step1 : step1;
10582 function max(values, valueof) {
10585 if (valueof === undefined) {
10586 var _iterator = _createForOfIteratorHelper(values),
10590 for (_iterator.s(); !(_step = _iterator.n()).done;) {
10591 var value = _step.value;
10593 if (value != null && (max < value || max === undefined && value >= value)) {
10605 var _iterator2 = _createForOfIteratorHelper(values),
10609 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
10610 var _value = _step2.value;
10612 if ((_value = valueof(_value, ++index, values)) != null && (max < _value || max === undefined && _value >= _value)) {
10626 function min$2(values, valueof) {
10629 if (valueof === undefined) {
10630 var _iterator = _createForOfIteratorHelper(values),
10634 for (_iterator.s(); !(_step = _iterator.n()).done;) {
10635 var value = _step.value;
10637 if (value != null && (min > value || min === undefined && value >= value)) {
10649 var _iterator2 = _createForOfIteratorHelper(values),
10653 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
10654 var _value = _step2.value;
10656 if ((_value = valueof(_value, ++index, values)) != null && (min > _value || min === undefined && _value >= _value)) {
10670 // ISC license, Copyright 2018 Vladimir Agafonkin.
10672 function quickselect$3(array, k) {
10673 var left = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
10674 var right = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : array.length - 1;
10675 var compare = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : d3_ascending;
10677 while (right > left) {
10678 if (right - left > 600) {
10679 var n = right - left + 1;
10680 var m = k - left + 1;
10681 var z = Math.log(n);
10682 var s = 0.5 * Math.exp(2 * z / 3);
10683 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
10684 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
10685 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
10686 quickselect$3(array, k, newLeft, newRight, compare);
10692 swap$1(array, left, k);
10693 if (compare(array[right], t) > 0) swap$1(array, left, right);
10696 swap$1(array, i, j), ++i, --j;
10698 while (compare(array[i], t) < 0) {
10702 while (compare(array[j], t) > 0) {
10707 if (compare(array[left], t) === 0) swap$1(array, left, j);else ++j, swap$1(array, j, right);
10708 if (j <= k) left = j + 1;
10709 if (k <= j) right = j - 1;
10715 function swap$1(array, i, j) {
10717 array[i] = array[j];
10721 function quantile(values, p, valueof) {
10722 values = Float64Array.from(numbers(values, valueof));
10723 if (!(n = values.length)) return;
10724 if ((p = +p) <= 0 || n < 2) return min$2(values);
10725 if (p >= 1) return max(values);
10728 i0 = Math.floor(i),
10729 value0 = max(quickselect$3(values, i0).subarray(0, i0 + 1)),
10730 value1 = min$2(values.subarray(i0 + 1));
10731 return value0 + (value1 - value0) * (i - i0);
10734 function d3_median (values, valueof) {
10735 return quantile(values, 0.5, valueof);
10738 var _marked$2 = /*#__PURE__*/regeneratorRuntime.mark(flatten);
10740 function flatten(arrays) {
10741 var _iterator, _step, array;
10743 return regeneratorRuntime.wrap(function flatten$(_context) {
10745 switch (_context.prev = _context.next) {
10747 _iterator = _createForOfIteratorHelper(arrays);
10753 if ((_step = _iterator.n()).done) {
10758 array = _step.value;
10759 return _context.delegateYield(array, "t0", 6);
10766 _context.next = 13;
10770 _context.prev = 10;
10771 _context.t1 = _context["catch"](1);
10773 _iterator.e(_context.t1);
10776 _context.prev = 13;
10780 return _context.finish(13);
10784 return _context.stop();
10787 }, _marked$2, null, [[1, 10, 13, 16]]);
10790 function merge$4(arrays) {
10791 return Array.from(flatten(arrays));
10794 function range$1 (start, stop, step) {
10795 start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
10797 n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
10798 range = new Array(n);
10801 range[i] = start + i * step;
10807 // `SameValue` abstract operation
10808 // https://tc39.es/ecma262/#sec-samevalue
10809 // eslint-disable-next-line es/no-object-is -- safe
10810 var sameValue$1 = Object.is || function is(x, y) {
10811 // eslint-disable-next-line no-self-compare -- NaN check
10812 return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
10817 // eslint-disable-next-line es/no-math-hypot -- required for testing
10818 var $hypot = Math.hypot;
10819 var abs$3 = Math.abs;
10820 var sqrt$1 = Math.sqrt;
10823 // https://bugs.chromium.org/p/v8/issues/detail?id=9546
10824 var BUGGY = !!$hypot && $hypot(Infinity, NaN) !== Infinity;
10826 // `Math.hypot` method
10827 // https://tc39.es/ecma262/#sec-math.hypot
10828 $$r({ target: 'Math', stat: true, forced: BUGGY }, {
10829 // eslint-disable-next-line no-unused-vars -- required for `.length`
10830 hypot: function hypot(value1, value2) {
10833 var aLen = arguments.length;
10837 arg = abs$3(arguments[i++]);
10840 sum = sum * div * div + 1;
10842 } else if (arg > 0) {
10847 return larg === Infinity ? Infinity : larg * sqrt$1(sum);
10851 // `Math.sign` method implementation
10852 // https://tc39.es/ecma262/#sec-math.sign
10853 // eslint-disable-next-line es/no-math-sign -- safe
10854 var mathSign = Math.sign || function sign(x) {
10855 // eslint-disable-next-line no-self-compare -- NaN check
10856 return (x = +x) == 0 || x != x ? x : x < 0 ? -1 : 1;
10860 var sign$1 = mathSign;
10862 // `Math.sign` method
10863 // https://tc39.es/ecma262/#sec-math.sign
10864 $$q({ target: 'Math', stat: true }, {
10868 var epsilon$1 = 1e-6;
10869 var epsilon2$1 = 1e-12;
10871 var halfPi = pi / 2;
10872 var quarterPi = pi / 4;
10874 var degrees$1 = 180 / pi;
10875 var radians = pi / 180;
10876 var abs$2 = Math.abs;
10877 var atan = Math.atan;
10878 var atan2 = Math.atan2;
10879 var cos = Math.cos;
10880 var exp$2 = Math.exp;
10881 var log$1 = Math.log;
10882 var sin = Math.sin;
10883 var sign = Math.sign || function (x) {
10884 return x > 0 ? 1 : x < 0 ? -1 : 0;
10886 var sqrt = Math.sqrt;
10887 var tan = Math.tan;
10889 return x > 1 ? 0 : x < -1 ? pi : Math.acos(x);
10892 return x > 1 ? halfPi : x < -1 ? -halfPi : Math.asin(x);
10895 function noop$1() {}
10897 function streamGeometry(geometry, stream) {
10898 if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
10899 streamGeometryType[geometry.type](geometry, stream);
10903 var streamObjectType = {
10904 Feature: function Feature(object, stream) {
10905 streamGeometry(object.geometry, stream);
10907 FeatureCollection: function FeatureCollection(object, stream) {
10908 var features = object.features,
10910 n = features.length;
10913 streamGeometry(features[i].geometry, stream);
10917 var streamGeometryType = {
10918 Sphere: function Sphere(object, stream) {
10921 Point: function Point(object, stream) {
10922 object = object.coordinates;
10923 stream.point(object[0], object[1], object[2]);
10925 MultiPoint: function MultiPoint(object, stream) {
10926 var coordinates = object.coordinates,
10928 n = coordinates.length;
10931 object = coordinates[i], stream.point(object[0], object[1], object[2]);
10934 LineString: function LineString(object, stream) {
10935 streamLine(object.coordinates, stream, 0);
10937 MultiLineString: function MultiLineString(object, stream) {
10938 var coordinates = object.coordinates,
10940 n = coordinates.length;
10943 streamLine(coordinates[i], stream, 0);
10946 Polygon: function Polygon(object, stream) {
10947 streamPolygon(object.coordinates, stream);
10949 MultiPolygon: function MultiPolygon(object, stream) {
10950 var coordinates = object.coordinates,
10952 n = coordinates.length;
10955 streamPolygon(coordinates[i], stream);
10958 GeometryCollection: function GeometryCollection(object, stream) {
10959 var geometries = object.geometries,
10961 n = geometries.length;
10964 streamGeometry(geometries[i], stream);
10969 function streamLine(coordinates, stream, closed) {
10971 n = coordinates.length - closed,
10973 stream.lineStart();
10976 coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
10982 function streamPolygon(coordinates, stream) {
10984 n = coordinates.length;
10985 stream.polygonStart();
10988 streamLine(coordinates[i], stream, 1);
10991 stream.polygonEnd();
10994 function d3_geoStream (object, stream) {
10995 if (object && streamObjectType.hasOwnProperty(object.type)) {
10996 streamObjectType[object.type](object, stream);
10998 streamGeometry(object, stream);
11002 var areaRingSum$1 = new Adder(); // hello?
11004 var areaSum$1 = new Adder(),
11010 var areaStream$1 = {
11014 polygonStart: function polygonStart() {
11015 areaRingSum$1 = new Adder();
11016 areaStream$1.lineStart = areaRingStart$1;
11017 areaStream$1.lineEnd = areaRingEnd$1;
11019 polygonEnd: function polygonEnd() {
11020 var areaRing = +areaRingSum$1;
11021 areaSum$1.add(areaRing < 0 ? tau + areaRing : areaRing);
11022 this.lineStart = this.lineEnd = this.point = noop$1;
11024 sphere: function sphere() {
11025 areaSum$1.add(tau);
11029 function areaRingStart$1() {
11030 areaStream$1.point = areaPointFirst$1;
11033 function areaRingEnd$1() {
11034 areaPoint$1(lambda00$1, phi00$1);
11037 function areaPointFirst$1(lambda, phi) {
11038 areaStream$1.point = areaPoint$1;
11039 lambda00$1 = lambda, phi00$1 = phi;
11040 lambda *= radians, phi *= radians;
11041 lambda0$2 = lambda, cosPhi0$1 = cos(phi = phi / 2 + quarterPi), sinPhi0$1 = sin(phi);
11044 function areaPoint$1(lambda, phi) {
11045 lambda *= radians, phi *= radians;
11046 phi = phi / 2 + quarterPi; // half the angular distance from south pole
11047 // Spherical excess E for a spherical triangle with vertices: south pole,
11048 // previous point, current point. Uses a formula derived from Cagnoli’s
11049 // theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
11051 var dLambda = lambda - lambda0$2,
11052 sdLambda = dLambda >= 0 ? 1 : -1,
11053 adLambda = sdLambda * dLambda,
11056 k = sinPhi0$1 * sinPhi,
11057 u = cosPhi0$1 * cosPhi + k * cos(adLambda),
11058 v = k * sdLambda * sin(adLambda);
11059 areaRingSum$1.add(atan2(v, u)); // Advance the previous points.
11061 lambda0$2 = lambda, cosPhi0$1 = cosPhi, sinPhi0$1 = sinPhi;
11064 function d3_geoArea (object) {
11065 areaSum$1 = new Adder();
11066 d3_geoStream(object, areaStream$1);
11067 return areaSum$1 * 2;
11070 function spherical(cartesian) {
11071 return [atan2(cartesian[1], cartesian[0]), asin(cartesian[2])];
11073 function cartesian(spherical) {
11074 var lambda = spherical[0],
11075 phi = spherical[1],
11077 return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
11079 function cartesianDot(a, b) {
11080 return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
11082 function cartesianCross(a, b) {
11083 return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
11086 function cartesianAddInPlace(a, b) {
11087 a[0] += b[0], a[1] += b[1], a[2] += b[2];
11089 function cartesianScale(vector, k) {
11090 return [vector[0] * k, vector[1] * k, vector[2] * k];
11093 function cartesianNormalizeInPlace(d) {
11094 var l = sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
11095 d[0] /= l, d[1] /= l, d[2] /= l;
11098 var lambda0$1, phi0, lambda1, phi1, // bounds
11099 lambda2, // previous lambda-coordinate
11100 lambda00, phi00, // first point
11101 p0, // previous 3D point
11102 deltaSum, ranges, range;
11103 var boundsStream$1 = {
11104 point: boundsPoint$1,
11105 lineStart: boundsLineStart,
11106 lineEnd: boundsLineEnd,
11107 polygonStart: function polygonStart() {
11108 boundsStream$1.point = boundsRingPoint;
11109 boundsStream$1.lineStart = boundsRingStart;
11110 boundsStream$1.lineEnd = boundsRingEnd;
11111 deltaSum = new Adder();
11112 areaStream$1.polygonStart();
11114 polygonEnd: function polygonEnd() {
11115 areaStream$1.polygonEnd();
11116 boundsStream$1.point = boundsPoint$1;
11117 boundsStream$1.lineStart = boundsLineStart;
11118 boundsStream$1.lineEnd = boundsLineEnd;
11119 if (areaRingSum$1 < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);else if (deltaSum > epsilon$1) phi1 = 90;else if (deltaSum < -epsilon$1) phi0 = -90;
11120 range[0] = lambda0$1, range[1] = lambda1;
11122 sphere: function sphere() {
11123 lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
11127 function boundsPoint$1(lambda, phi) {
11128 ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
11129 if (phi < phi0) phi0 = phi;
11130 if (phi > phi1) phi1 = phi;
11133 function linePoint(lambda, phi) {
11134 var p = cartesian([lambda * radians, phi * radians]);
11137 var normal = cartesianCross(p0, p),
11138 equatorial = [normal[1], -normal[0], 0],
11139 inflection = cartesianCross(equatorial, normal);
11140 cartesianNormalizeInPlace(inflection);
11141 inflection = spherical(inflection);
11142 var delta = lambda - lambda2,
11143 sign = delta > 0 ? 1 : -1,
11144 lambdai = inflection[0] * degrees$1 * sign,
11146 antimeridian = abs$2(delta) > 180;
11148 if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
11149 phii = inflection[1] * degrees$1;
11150 if (phii > phi1) phi1 = phii;
11151 } else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
11152 phii = -inflection[1] * degrees$1;
11153 if (phii < phi0) phi0 = phii;
11155 if (phi < phi0) phi0 = phi;
11156 if (phi > phi1) phi1 = phi;
11159 if (antimeridian) {
11160 if (lambda < lambda2) {
11161 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
11163 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
11166 if (lambda1 >= lambda0$1) {
11167 if (lambda < lambda0$1) lambda0$1 = lambda;
11168 if (lambda > lambda1) lambda1 = lambda;
11170 if (lambda > lambda2) {
11171 if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
11173 if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
11178 ranges.push(range = [lambda0$1 = lambda, lambda1 = lambda]);
11181 if (phi < phi0) phi0 = phi;
11182 if (phi > phi1) phi1 = phi;
11183 p0 = p, lambda2 = lambda;
11186 function boundsLineStart() {
11187 boundsStream$1.point = linePoint;
11190 function boundsLineEnd() {
11191 range[0] = lambda0$1, range[1] = lambda1;
11192 boundsStream$1.point = boundsPoint$1;
11196 function boundsRingPoint(lambda, phi) {
11198 var delta = lambda - lambda2;
11199 deltaSum.add(abs$2(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
11201 lambda00 = lambda, phi00 = phi;
11204 areaStream$1.point(lambda, phi);
11205 linePoint(lambda, phi);
11208 function boundsRingStart() {
11209 areaStream$1.lineStart();
11212 function boundsRingEnd() {
11213 boundsRingPoint(lambda00, phi00);
11214 areaStream$1.lineEnd();
11215 if (abs$2(deltaSum) > epsilon$1) lambda0$1 = -(lambda1 = 180);
11216 range[0] = lambda0$1, range[1] = lambda1;
11218 } // Finds the left-right distance between two longitudes.
11219 // This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
11220 // the distance between ±180° to be 360°.
11223 function angle(lambda0, lambda1) {
11224 return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
11227 function rangeCompare(a, b) {
11228 return a[0] - b[0];
11231 function rangeContains(range, x) {
11232 return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
11235 function d3_geoBounds (feature) {
11236 var i, n, a, b, merged, deltaMax, delta;
11237 phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
11239 d3_geoStream(feature, boundsStream$1); // First, sort ranges by their minimum longitudes.
11241 if (n = ranges.length) {
11242 ranges.sort(rangeCompare); // Then, merge any ranges that overlap.
11244 for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
11247 if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
11248 if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
11249 if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
11251 merged.push(a = b);
11253 } // Finally, find the largest gap between the merged ranges.
11254 // The final bounding box will be the inverse of this gap.
11257 for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
11259 if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
11263 ranges = range = null;
11264 return lambda0$1 === Infinity || phi0 === Infinity ? [[NaN, NaN], [NaN, NaN]] : [[lambda0$1, phi0], [lambda1, phi1]];
11267 function compose (a, b) {
11268 function compose(x, y) {
11269 return x = a(x, y), b(x[0], x[1]);
11272 if (a.invert && b.invert) compose.invert = function (x, y) {
11273 return x = b.invert(x, y), x && a.invert(x[0], x[1]);
11278 function rotationIdentity(lambda, phi) {
11279 return [abs$2(lambda) > pi ? lambda + Math.round(-lambda / tau) * tau : lambda, phi];
11282 rotationIdentity.invert = rotationIdentity;
11283 function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
11284 return (deltaLambda %= tau) ? deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma)) : rotationLambda(deltaLambda) : deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma) : rotationIdentity;
11287 function forwardRotationLambda(deltaLambda) {
11288 return function (lambda, phi) {
11289 return lambda += deltaLambda, [lambda > pi ? lambda - tau : lambda < -pi ? lambda + tau : lambda, phi];
11293 function rotationLambda(deltaLambda) {
11294 var rotation = forwardRotationLambda(deltaLambda);
11295 rotation.invert = forwardRotationLambda(-deltaLambda);
11299 function rotationPhiGamma(deltaPhi, deltaGamma) {
11300 var cosDeltaPhi = cos(deltaPhi),
11301 sinDeltaPhi = sin(deltaPhi),
11302 cosDeltaGamma = cos(deltaGamma),
11303 sinDeltaGamma = sin(deltaGamma);
11305 function rotation(lambda, phi) {
11306 var cosPhi = cos(phi),
11307 x = cos(lambda) * cosPhi,
11308 y = sin(lambda) * cosPhi,
11310 k = z * cosDeltaPhi + x * sinDeltaPhi;
11311 return [atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi), asin(k * cosDeltaGamma + y * sinDeltaGamma)];
11314 rotation.invert = function (lambda, phi) {
11315 var cosPhi = cos(phi),
11316 x = cos(lambda) * cosPhi,
11317 y = sin(lambda) * cosPhi,
11319 k = z * cosDeltaGamma - y * sinDeltaGamma;
11320 return [atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi), asin(k * cosDeltaPhi - x * sinDeltaPhi)];
11326 function rotation (rotate) {
11327 rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
11329 function forward(coordinates) {
11330 coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
11331 return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
11334 forward.invert = function (coordinates) {
11335 coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
11336 return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
11342 function circleStream(stream, radius, delta, direction, t0, t1) {
11343 if (!delta) return;
11344 var cosRadius = cos(radius),
11345 sinRadius = sin(radius),
11346 step = direction * delta;
11349 t0 = radius + direction * tau;
11350 t1 = radius - step / 2;
11352 t0 = circleRadius(cosRadius, t0);
11353 t1 = circleRadius(cosRadius, t1);
11354 if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau;
11357 for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
11358 point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
11359 stream.point(point[0], point[1]);
11361 } // Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
11363 function circleRadius(cosRadius, point) {
11364 point = cartesian(point), point[0] -= cosRadius;
11365 cartesianNormalizeInPlace(point);
11366 var radius = acos(-point[1]);
11367 return ((-point[2] < 0 ? -radius : radius) + tau - epsilon$1) % tau;
11370 function clipBuffer () {
11374 point: function point(x, y, m) {
11375 line.push([x, y, m]);
11377 lineStart: function lineStart() {
11378 lines.push(line = []);
11381 rejoin: function rejoin() {
11382 if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
11384 result: function result() {
11385 var result = lines;
11393 function pointEqual (a, b) {
11394 return abs$2(a[0] - b[0]) < epsilon$1 && abs$2(a[1] - b[1]) < epsilon$1;
11397 function Intersection(point, points, other, entry) {
11400 this.o = other; // another intersection
11402 this.e = entry; // is an entry?
11404 this.v = false; // visited
11406 this.n = this.p = null; // next & previous
11407 } // A generalized polygon clipping algorithm: given a polygon that has been cut
11408 // into its visible line segments, and rejoins the segments by interpolating
11409 // along the clip edge.
11412 function clipRejoin (segments, compareIntersection, startInside, interpolate, stream) {
11417 segments.forEach(function (segment) {
11418 if ((n = segment.length - 1) <= 0) return;
11424 if (pointEqual(p0, p1)) {
11425 if (!p0[2] && !p1[2]) {
11426 stream.lineStart();
11428 for (i = 0; i < n; ++i) {
11429 stream.point((p0 = segment[i])[0], p0[1]);
11434 } // handle degenerate cases by moving the point
11437 p1[0] += 2 * epsilon$1;
11440 subject.push(x = new Intersection(p0, segment, null, true));
11441 clip.push(x.o = new Intersection(p0, null, x, false));
11442 subject.push(x = new Intersection(p1, segment, null, false));
11443 clip.push(x.o = new Intersection(p1, null, x, true));
11445 if (!subject.length) return;
11446 clip.sort(compareIntersection);
11450 for (i = 0, n = clip.length; i < n; ++i) {
11451 clip[i].e = startInside = !startInside;
11454 var start = subject[0],
11459 // Find first unvisited intersection.
11460 var current = start,
11463 while (current.v) {
11464 if ((current = current.n) === start) return;
11467 points = current.z;
11468 stream.lineStart();
11471 current.v = current.o.v = true;
11475 for (i = 0, n = points.length; i < n; ++i) {
11476 stream.point((point = points[i])[0], point[1]);
11479 interpolate(current.x, current.n.x, 1, stream);
11482 current = current.n;
11485 points = current.p.z;
11487 for (i = points.length - 1; i >= 0; --i) {
11488 stream.point((point = points[i])[0], point[1]);
11491 interpolate(current.x, current.p.x, -1, stream);
11494 current = current.p;
11497 current = current.o;
11498 points = current.z;
11499 isSubject = !isSubject;
11500 } while (!current.v);
11506 function link(array) {
11507 if (!(n = array.length)) return;
11514 a.n = b = array[i];
11519 a.n = b = array[0];
11523 function longitude(point) {
11524 if (abs$2(point[0]) <= pi) return point[0];else return sign(point[0]) * ((abs$2(point[0]) + pi) % tau - pi);
11527 function polygonContains (polygon, point) {
11528 var lambda = longitude(point),
11531 normal = [sin(lambda), -cos(lambda), 0],
11534 var sum = new Adder();
11535 if (sinPhi === 1) phi = halfPi + epsilon$1;else if (sinPhi === -1) phi = -halfPi - epsilon$1;
11537 for (var i = 0, n = polygon.length; i < n; ++i) {
11538 if (!(m = (ring = polygon[i]).length)) continue;
11541 point0 = ring[m - 1],
11542 lambda0 = longitude(point0),
11543 phi0 = point0[1] / 2 + quarterPi,
11544 sinPhi0 = sin(phi0),
11545 cosPhi0 = cos(phi0);
11547 for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
11548 var point1 = ring[j],
11549 lambda1 = longitude(point1),
11550 phi1 = point1[1] / 2 + quarterPi,
11551 sinPhi1 = sin(phi1),
11552 cosPhi1 = cos(phi1),
11553 delta = lambda1 - lambda0,
11554 sign = delta >= 0 ? 1 : -1,
11555 absDelta = sign * delta,
11556 antimeridian = absDelta > pi,
11557 k = sinPhi0 * sinPhi1;
11558 sum.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
11559 angle += antimeridian ? delta + sign * tau : delta; // Are the longitudes either side of the point’s meridian (lambda),
11560 // and are the latitudes smaller than the parallel (phi)?
11562 if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
11563 var arc = cartesianCross(cartesian(point0), cartesian(point1));
11564 cartesianNormalizeInPlace(arc);
11565 var intersection = cartesianCross(normal, arc);
11566 cartesianNormalizeInPlace(intersection);
11567 var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin(intersection[2]);
11569 if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
11570 winding += antimeridian ^ delta >= 0 ? 1 : -1;
11574 } // First, determine whether the South pole is inside or outside:
11576 // It is inside if:
11577 // * the polygon winds around it in a clockwise direction.
11578 // * the polygon does not (cumulatively) wind around it, but has a negative
11579 // (counter-clockwise) area.
11581 // Second, count the (signed) number of times a segment crosses a lambda
11582 // from the point to the South pole. If it is zero, then the point is the
11583 // same side as the South pole.
11586 return (angle < -epsilon$1 || angle < epsilon$1 && sum < -epsilon2$1) ^ winding & 1;
11589 function clip (pointVisible, clipLine, interpolate, start) {
11590 return function (sink) {
11591 var line = clipLine(sink),
11592 ringBuffer = clipBuffer(),
11593 ringSink = clipLine(ringBuffer),
11594 polygonStarted = false,
11600 lineStart: lineStart,
11602 polygonStart: function polygonStart() {
11603 clip.point = pointRing;
11604 clip.lineStart = ringStart;
11605 clip.lineEnd = ringEnd;
11609 polygonEnd: function polygonEnd() {
11610 clip.point = point;
11611 clip.lineStart = lineStart;
11612 clip.lineEnd = lineEnd;
11613 segments = merge$4(segments);
11614 var startInside = polygonContains(polygon, start);
11616 if (segments.length) {
11617 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11618 clipRejoin(segments, compareIntersection, startInside, interpolate, sink);
11619 } else if (startInside) {
11620 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11622 interpolate(null, null, 1, sink);
11626 if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
11627 segments = polygon = null;
11629 sphere: function sphere() {
11630 sink.polygonStart();
11632 interpolate(null, null, 1, sink);
11638 function point(lambda, phi) {
11639 if (pointVisible(lambda, phi)) sink.point(lambda, phi);
11642 function pointLine(lambda, phi) {
11643 line.point(lambda, phi);
11646 function lineStart() {
11647 clip.point = pointLine;
11651 function lineEnd() {
11652 clip.point = point;
11656 function pointRing(lambda, phi) {
11657 ring.push([lambda, phi]);
11658 ringSink.point(lambda, phi);
11661 function ringStart() {
11662 ringSink.lineStart();
11666 function ringEnd() {
11667 pointRing(ring[0][0], ring[0][1]);
11668 ringSink.lineEnd();
11669 var clean = ringSink.clean(),
11670 ringSegments = ringBuffer.result(),
11672 n = ringSegments.length,
11677 polygon.push(ring);
11679 if (!n) return; // No intersections.
11682 segment = ringSegments[0];
11684 if ((m = segment.length - 1) > 0) {
11685 if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
11688 for (i = 0; i < m; ++i) {
11689 sink.point((point = segment[i])[0], point[1]);
11696 } // Rejoin connected segments.
11697 // TODO reuse ringBuffer.rejoin()?
11700 if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
11701 segments.push(ringSegments.filter(validSegment));
11708 function validSegment(segment) {
11709 return segment.length > 1;
11710 } // Intersections are sorted along the clip edge. For both antimeridian cutting
11711 // and circle clipping, the same comparison is used.
11714 function compareIntersection(a, b) {
11715 return ((a = a.x)[0] < 0 ? a[1] - halfPi - epsilon$1 : halfPi - a[1]) - ((b = b.x)[0] < 0 ? b[1] - halfPi - epsilon$1 : halfPi - b[1]);
11718 var clipAntimeridian = clip(function () {
11720 }, clipAntimeridianLine, clipAntimeridianInterpolate, [-pi, -halfPi]); // Takes a line and cuts into visible segments. Return values: 0 - there were
11721 // intersections or the line was empty; 1 - no intersections; 2 - there were
11722 // intersections, and the first and last segments should be rejoined.
11724 function clipAntimeridianLine(stream) {
11728 _clean; // no intersections
11732 lineStart: function lineStart() {
11733 stream.lineStart();
11736 point: function point(lambda1, phi1) {
11737 var sign1 = lambda1 > 0 ? pi : -pi,
11738 delta = abs$2(lambda1 - lambda0);
11740 if (abs$2(delta - pi) < epsilon$1) {
11741 // line crosses a pole
11742 stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi : -halfPi);
11743 stream.point(sign0, phi0);
11745 stream.lineStart();
11746 stream.point(sign1, phi0);
11747 stream.point(lambda1, phi0);
11749 } else if (sign0 !== sign1 && delta >= pi) {
11750 // line crosses antimeridian
11751 if (abs$2(lambda0 - sign0) < epsilon$1) lambda0 -= sign0 * epsilon$1; // handle degeneracies
11753 if (abs$2(lambda1 - sign1) < epsilon$1) lambda1 -= sign1 * epsilon$1;
11754 phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
11755 stream.point(sign0, phi0);
11757 stream.lineStart();
11758 stream.point(sign1, phi0);
11762 stream.point(lambda0 = lambda1, phi0 = phi1);
11765 lineEnd: function lineEnd() {
11767 lambda0 = phi0 = NaN;
11769 clean: function clean() {
11770 return 2 - _clean; // if intersections, rejoin first and last segments
11775 function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
11778 sinLambda0Lambda1 = sin(lambda0 - lambda1);
11779 return abs$2(sinLambda0Lambda1) > epsilon$1 ? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1) - sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0)) / (cosPhi0 * cosPhi1 * sinLambda0Lambda1)) : (phi0 + phi1) / 2;
11782 function clipAntimeridianInterpolate(from, to, direction, stream) {
11785 if (from == null) {
11786 phi = direction * halfPi;
11787 stream.point(-pi, phi);
11788 stream.point(0, phi);
11789 stream.point(pi, phi);
11790 stream.point(pi, 0);
11791 stream.point(pi, -phi);
11792 stream.point(0, -phi);
11793 stream.point(-pi, -phi);
11794 stream.point(-pi, 0);
11795 stream.point(-pi, phi);
11796 } else if (abs$2(from[0] - to[0]) > epsilon$1) {
11797 var lambda = from[0] < to[0] ? pi : -pi;
11798 phi = direction * lambda / 2;
11799 stream.point(-lambda, phi);
11800 stream.point(0, phi);
11801 stream.point(lambda, phi);
11803 stream.point(to[0], to[1]);
11807 function clipCircle (radius) {
11808 var cr = cos(radius),
11809 delta = 6 * radians,
11810 smallRadius = cr > 0,
11811 notHemisphere = abs$2(cr) > epsilon$1; // TODO optimise for this common case
11813 function interpolate(from, to, direction, stream) {
11814 circleStream(stream, radius, delta, direction, from, to);
11817 function visible(lambda, phi) {
11818 return cos(lambda) * cos(phi) > cr;
11819 } // Takes a line and cuts into visible segments. Return values used for polygon
11820 // clipping: 0 - there were intersections or the line was empty; 1 - no
11821 // intersections 2 - there were intersections, and the first and last segments
11822 // should be rejoined.
11825 function clipLine(stream) {
11826 var point0, // previous point
11827 c0, // code for previous point
11828 v0, // visibility of previous point
11829 v00, // visibility of first point
11830 _clean; // no intersections
11834 lineStart: function lineStart() {
11838 point: function point(lambda, phi) {
11839 var point1 = [lambda, phi],
11841 v = visible(lambda, phi),
11842 c = smallRadius ? v ? 0 : code(lambda, phi) : v ? code(lambda + (lambda < 0 ? pi : -pi), phi) : 0;
11843 if (!point0 && (v00 = v0 = v)) stream.lineStart();
11846 point2 = intersect(point0, point1);
11847 if (!point2 || pointEqual(point0, point2) || pointEqual(point1, point2)) point1[2] = 1;
11854 // outside going in
11855 stream.lineStart();
11856 point2 = intersect(point1, point0);
11857 stream.point(point2[0], point2[1]);
11859 // inside going out
11860 point2 = intersect(point0, point1);
11861 stream.point(point2[0], point2[1], 2);
11866 } else if (notHemisphere && point0 && smallRadius ^ v) {
11867 var t; // If the codes for two points are different, or are both zero,
11868 // and there this segment intersects with the small circle.
11870 if (!(c & c0) && (t = intersect(point1, point0, true))) {
11874 stream.lineStart();
11875 stream.point(t[0][0], t[0][1]);
11876 stream.point(t[1][0], t[1][1]);
11879 stream.point(t[1][0], t[1][1]);
11881 stream.lineStart();
11882 stream.point(t[0][0], t[0][1], 3);
11887 if (v && (!point0 || !pointEqual(point0, point1))) {
11888 stream.point(point1[0], point1[1]);
11891 point0 = point1, v0 = v, c0 = c;
11893 lineEnd: function lineEnd() {
11894 if (v0) stream.lineEnd();
11897 // Rejoin first and last segments if there were intersections and the first
11898 // and last points were visible.
11899 clean: function clean() {
11900 return _clean | (v00 && v0) << 1;
11903 } // Intersects the great circle between a and b with the clip circle.
11906 function intersect(a, b, two) {
11907 var pa = cartesian(a),
11908 pb = cartesian(b); // We have two planes, n1.p = d1 and n2.p = d2.
11909 // Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
11911 var n1 = [1, 0, 0],
11913 n2 = cartesianCross(pa, pb),
11914 n2n2 = cartesianDot(n2, n2),
11916 // cartesianDot(n1, n2),
11917 determinant = n2n2 - n1n2 * n1n2; // Two polar points.
11919 if (!determinant) return !two && a;
11920 var c1 = cr * n2n2 / determinant,
11921 c2 = -cr * n1n2 / determinant,
11922 n1xn2 = cartesianCross(n1, n2),
11923 A = cartesianScale(n1, c1),
11924 B = cartesianScale(n2, c2);
11925 cartesianAddInPlace(A, B); // Solve |p(t)|^2 = 1.
11928 w = cartesianDot(A, u),
11929 uu = cartesianDot(u, u),
11930 t2 = w * w - uu * (cartesianDot(A, A) - 1);
11931 if (t2 < 0) return;
11933 q = cartesianScale(u, (-w - t) / uu);
11934 cartesianAddInPlace(q, A);
11936 if (!two) return q; // Two intersection points.
11938 var lambda0 = a[0],
11943 if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
11944 var delta = lambda1 - lambda0,
11945 polar = abs$2(delta - pi) < epsilon$1,
11946 meridian = polar || delta < epsilon$1;
11947 if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z; // Check that the first point is between a and b.
11949 if (meridian ? polar ? phi0 + phi1 > 0 ^ q[1] < (abs$2(q[0] - lambda0) < epsilon$1 ? phi0 : phi1) : phi0 <= q[1] && q[1] <= phi1 : delta > pi ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
11950 var q1 = cartesianScale(u, (-w + t) / uu);
11951 cartesianAddInPlace(q1, A);
11952 return [q, spherical(q1)];
11954 } // Generates a 4-bit vector representing the location of a point relative to
11955 // the small circle's bounding box.
11958 function code(lambda, phi) {
11959 var r = smallRadius ? radius : pi - radius,
11961 if (lambda < -r) code |= 1; // left
11962 else if (lambda > r) code |= 2; // right
11964 if (phi < -r) code |= 4; // below
11965 else if (phi > r) code |= 8; // above
11970 return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi, radius - pi]);
11973 function clipLine (a, b, x0, y0, x1, y1) {
11984 if (!dx && r > 0) return;
11988 if (r < t0) return;
11989 if (r < t1) t1 = r;
11990 } else if (dx > 0) {
11991 if (r > t1) return;
11992 if (r > t0) t0 = r;
11996 if (!dx && r < 0) return;
12000 if (r > t1) return;
12001 if (r > t0) t0 = r;
12002 } else if (dx > 0) {
12003 if (r < t0) return;
12004 if (r < t1) t1 = r;
12008 if (!dy && r > 0) return;
12012 if (r < t0) return;
12013 if (r < t1) t1 = r;
12014 } else if (dy > 0) {
12015 if (r > t1) return;
12016 if (r > t0) t0 = r;
12020 if (!dy && r < 0) return;
12024 if (r > t1) return;
12025 if (r > t0) t0 = r;
12026 } else if (dy > 0) {
12027 if (r < t0) return;
12028 if (r < t1) t1 = r;
12031 if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
12032 if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
12037 clipMin = -clipMax; // TODO Use d3-polygon’s polygonContains here for the ring check?
12038 // TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
12040 function clipRectangle(x0, y0, x1, y1) {
12041 function visible(x, y) {
12042 return x0 <= x && x <= x1 && y0 <= y && y <= y1;
12045 function interpolate(from, to, direction, stream) {
12049 if (from == null || (a = corner(from, direction)) !== (a1 = corner(to, direction)) || comparePoint(from, to) < 0 ^ direction > 0) {
12051 stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
12052 } while ((a = (a + direction + 4) % 4) !== a1);
12054 stream.point(to[0], to[1]);
12058 function corner(p, direction) {
12059 return abs$2(p[0] - x0) < epsilon$1 ? direction > 0 ? 0 : 3 : abs$2(p[0] - x1) < epsilon$1 ? direction > 0 ? 2 : 1 : abs$2(p[1] - y0) < epsilon$1 ? direction > 0 ? 1 : 0 : direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
12062 function compareIntersection(a, b) {
12063 return comparePoint(a.x, b.x);
12066 function comparePoint(a, b) {
12067 var ca = corner(a, 1),
12069 return ca !== cb ? ca - cb : ca === 0 ? b[1] - a[1] : ca === 1 ? a[0] - b[0] : ca === 2 ? a[1] - b[1] : b[0] - a[0];
12072 return function (stream) {
12073 var activeStream = stream,
12074 bufferStream = clipBuffer(),
12090 lineStart: lineStart,
12092 polygonStart: polygonStart,
12093 polygonEnd: polygonEnd
12096 function point(x, y) {
12097 if (visible(x, y)) activeStream.point(x, y);
12100 function polygonInside() {
12103 for (var i = 0, n = polygon.length; i < n; ++i) {
12104 for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
12105 a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
12108 if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding;
12110 if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding;
12116 } // Buffer geometry within a polygon and then clip it en masse.
12119 function polygonStart() {
12120 activeStream = bufferStream, segments = [], polygon = [], clean = true;
12123 function polygonEnd() {
12124 var startInside = polygonInside(),
12125 cleanInside = clean && startInside,
12126 visible = (segments = merge$4(segments)).length;
12128 if (cleanInside || visible) {
12129 stream.polygonStart();
12132 stream.lineStart();
12133 interpolate(null, null, 1, stream);
12138 clipRejoin(segments, compareIntersection, startInside, interpolate, stream);
12141 stream.polygonEnd();
12144 activeStream = stream, segments = polygon = ring = null;
12147 function lineStart() {
12148 clipStream.point = linePoint;
12149 if (polygon) polygon.push(ring = []);
12153 } // TODO rather than special-case polygons, simply handle them separately.
12154 // Ideally, coincident intersection points should be jittered to avoid
12155 // clipping issues.
12158 function lineEnd() {
12160 linePoint(x__, y__);
12161 if (v__ && v_) bufferStream.rejoin();
12162 segments.push(bufferStream.result());
12165 clipStream.point = point;
12166 if (v_) activeStream.lineEnd();
12169 function linePoint(x, y) {
12170 var v = visible(x, y);
12171 if (polygon) ring.push([x, y]);
12174 x__ = x, y__ = y, v__ = v;
12178 activeStream.lineStart();
12179 activeStream.point(x, y);
12182 if (v && v_) activeStream.point(x, y);else {
12183 var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
12184 b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
12186 if (clipLine(a, b, x0, y0, x1, y1)) {
12188 activeStream.lineStart();
12189 activeStream.point(a[0], a[1]);
12192 activeStream.point(b[0], b[1]);
12193 if (!v) activeStream.lineEnd();
12196 activeStream.lineStart();
12197 activeStream.point(x, y);
12203 x_ = x, y_ = y, v_ = v;
12210 var lengthSum$1, lambda0, sinPhi0, cosPhi0;
12211 var lengthStream$1 = {
12214 lineStart: lengthLineStart,
12216 polygonStart: noop$1,
12220 function lengthLineStart() {
12221 lengthStream$1.point = lengthPointFirst$1;
12222 lengthStream$1.lineEnd = lengthLineEnd;
12225 function lengthLineEnd() {
12226 lengthStream$1.point = lengthStream$1.lineEnd = noop$1;
12229 function lengthPointFirst$1(lambda, phi) {
12230 lambda *= radians, phi *= radians;
12231 lambda0 = lambda, sinPhi0 = sin(phi), cosPhi0 = cos(phi);
12232 lengthStream$1.point = lengthPoint$1;
12235 function lengthPoint$1(lambda, phi) {
12236 lambda *= radians, phi *= radians;
12237 var sinPhi = sin(phi),
12239 delta = abs$2(lambda - lambda0),
12240 cosDelta = cos(delta),
12241 sinDelta = sin(delta),
12242 x = cosPhi * sinDelta,
12243 y = cosPhi0 * sinPhi - sinPhi0 * cosPhi * cosDelta,
12244 z = sinPhi0 * sinPhi + cosPhi0 * cosPhi * cosDelta;
12245 lengthSum$1.add(atan2(sqrt(x * x + y * y), z));
12246 lambda0 = lambda, sinPhi0 = sinPhi, cosPhi0 = cosPhi;
12249 function d3_geoLength (object) {
12250 lengthSum$1 = new Adder();
12251 d3_geoStream(object, lengthStream$1);
12252 return +lengthSum$1;
12255 var identity$4 = (function (x) {
12259 var areaSum = new Adder(),
12260 areaRingSum = new Adder(),
12269 polygonStart: function polygonStart() {
12270 areaStream.lineStart = areaRingStart;
12271 areaStream.lineEnd = areaRingEnd;
12273 polygonEnd: function polygonEnd() {
12274 areaStream.lineStart = areaStream.lineEnd = areaStream.point = noop$1;
12275 areaSum.add(abs$2(areaRingSum));
12276 areaRingSum = new Adder();
12278 result: function result() {
12279 var area = areaSum / 2;
12280 areaSum = new Adder();
12285 function areaRingStart() {
12286 areaStream.point = areaPointFirst;
12289 function areaPointFirst(x, y) {
12290 areaStream.point = areaPoint;
12291 x00$2 = x0$3 = x, y00$2 = y0$3 = y;
12294 function areaPoint(x, y) {
12295 areaRingSum.add(y0$3 * x - x0$3 * y);
12296 x0$3 = x, y0$3 = y;
12299 function areaRingEnd() {
12300 areaPoint(x00$2, y00$2);
12303 var x0$2 = Infinity,
12307 var boundsStream = {
12308 point: boundsPoint,
12311 polygonStart: noop$1,
12312 polygonEnd: noop$1,
12313 result: function result() {
12314 var bounds = [[x0$2, y0$2], [x1, y1]];
12315 x1 = y1 = -(y0$2 = x0$2 = Infinity);
12320 function boundsPoint(x, y) {
12321 if (x < x0$2) x0$2 = x;
12322 if (x > x1) x1 = x;
12323 if (y < y0$2) y0$2 = y;
12324 if (y > y1) y1 = y;
12340 var centroidStream = {
12341 point: centroidPoint,
12342 lineStart: centroidLineStart,
12343 lineEnd: centroidLineEnd,
12344 polygonStart: function polygonStart() {
12345 centroidStream.lineStart = centroidRingStart;
12346 centroidStream.lineEnd = centroidRingEnd;
12348 polygonEnd: function polygonEnd() {
12349 centroidStream.point = centroidPoint;
12350 centroidStream.lineStart = centroidLineStart;
12351 centroidStream.lineEnd = centroidLineEnd;
12353 result: function result() {
12354 var centroid = Z2 ? [X2 / Z2, Y2 / Z2] : Z1 ? [X1 / Z1, Y1 / Z1] : Z0 ? [X0 / Z0, Y0 / Z0] : [NaN, NaN];
12355 X0 = Y0 = Z0 = X1 = Y1 = Z1 = X2 = Y2 = Z2 = 0;
12360 function centroidPoint(x, y) {
12366 function centroidLineStart() {
12367 centroidStream.point = centroidPointFirstLine;
12370 function centroidPointFirstLine(x, y) {
12371 centroidStream.point = centroidPointLine;
12372 centroidPoint(x0$1 = x, y0$1 = y);
12375 function centroidPointLine(x, y) {
12378 z = sqrt(dx * dx + dy * dy);
12379 X1 += z * (x0$1 + x) / 2;
12380 Y1 += z * (y0$1 + y) / 2;
12382 centroidPoint(x0$1 = x, y0$1 = y);
12385 function centroidLineEnd() {
12386 centroidStream.point = centroidPoint;
12389 function centroidRingStart() {
12390 centroidStream.point = centroidPointFirstRing;
12393 function centroidRingEnd() {
12394 centroidPointRing(x00$1, y00$1);
12397 function centroidPointFirstRing(x, y) {
12398 centroidStream.point = centroidPointRing;
12399 centroidPoint(x00$1 = x0$1 = x, y00$1 = y0$1 = y);
12402 function centroidPointRing(x, y) {
12405 z = sqrt(dx * dx + dy * dy);
12406 X1 += z * (x0$1 + x) / 2;
12407 Y1 += z * (y0$1 + y) / 2;
12409 z = y0$1 * x - x0$1 * y;
12410 X2 += z * (x0$1 + x);
12411 Y2 += z * (y0$1 + y);
12413 centroidPoint(x0$1 = x, y0$1 = y);
12416 function PathContext(context) {
12417 this._context = context;
12419 PathContext.prototype = {
12421 pointRadius: function pointRadius(_) {
12422 return this._radius = _, this;
12424 polygonStart: function polygonStart() {
12427 polygonEnd: function polygonEnd() {
12430 lineStart: function lineStart() {
12433 lineEnd: function lineEnd() {
12434 if (this._line === 0) this._context.closePath();
12437 point: function point(x, y) {
12438 switch (this._point) {
12441 this._context.moveTo(x, y);
12449 this._context.lineTo(x, y);
12456 this._context.moveTo(x + this._radius, y);
12458 this._context.arc(x, y, this._radius, 0, tau);
12467 var lengthSum = new Adder(),
12473 var lengthStream = {
12475 lineStart: function lineStart() {
12476 lengthStream.point = lengthPointFirst;
12478 lineEnd: function lineEnd() {
12479 if (lengthRing) lengthPoint(x00, y00);
12480 lengthStream.point = noop$1;
12482 polygonStart: function polygonStart() {
12485 polygonEnd: function polygonEnd() {
12488 result: function result() {
12489 var length = +lengthSum;
12490 lengthSum = new Adder();
12495 function lengthPointFirst(x, y) {
12496 lengthStream.point = lengthPoint;
12497 x00 = x0 = x, y00 = y0 = y;
12500 function lengthPoint(x, y) {
12502 lengthSum.add(sqrt(x0 * x0 + y0 * y0));
12506 function PathString() {
12509 PathString.prototype = {
12511 _circle: circle(4.5),
12512 pointRadius: function pointRadius(_) {
12513 if ((_ = +_) !== this._radius) this._radius = _, this._circle = null;
12516 polygonStart: function polygonStart() {
12519 polygonEnd: function polygonEnd() {
12522 lineStart: function lineStart() {
12525 lineEnd: function lineEnd() {
12526 if (this._line === 0) this._string.push("Z");
12529 point: function point(x, y) {
12530 switch (this._point) {
12533 this._string.push("M", x, ",", y);
12541 this._string.push("L", x, ",", y);
12548 if (this._circle == null) this._circle = circle(this._radius);
12550 this._string.push("M", x, ",", y, this._circle);
12556 result: function result() {
12557 if (this._string.length) {
12558 var result = this._string.join("");
12568 function circle(radius) {
12569 return "m0," + radius + "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius + "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius + "z";
12572 function d3_geoPath (projection, context) {
12573 var pointRadius = 4.5,
12577 function path(object) {
12579 if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
12580 d3_geoStream(object, projectionStream(contextStream));
12583 return contextStream.result();
12586 path.area = function (object) {
12587 d3_geoStream(object, projectionStream(areaStream));
12588 return areaStream.result();
12591 path.measure = function (object) {
12592 d3_geoStream(object, projectionStream(lengthStream));
12593 return lengthStream.result();
12596 path.bounds = function (object) {
12597 d3_geoStream(object, projectionStream(boundsStream));
12598 return boundsStream.result();
12601 path.centroid = function (object) {
12602 d3_geoStream(object, projectionStream(centroidStream));
12603 return centroidStream.result();
12606 path.projection = function (_) {
12607 return arguments.length ? (projectionStream = _ == null ? (projection = null, identity$4) : (projection = _).stream, path) : projection;
12610 path.context = function (_) {
12611 if (!arguments.length) return context;
12612 contextStream = _ == null ? (context = null, new PathString()) : new PathContext(context = _);
12613 if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
12617 path.pointRadius = function (_) {
12618 if (!arguments.length) return pointRadius;
12619 pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
12623 return path.projection(projection).context(context);
12626 function d3_geoTransform (methods) {
12628 stream: transformer$1(methods)
12631 function transformer$1(methods) {
12632 return function (stream) {
12633 var s = new TransformStream();
12635 for (var key in methods) {
12636 s[key] = methods[key];
12644 function TransformStream() {}
12646 TransformStream.prototype = {
12647 constructor: TransformStream,
12648 point: function point(x, y) {
12649 this.stream.point(x, y);
12651 sphere: function sphere() {
12652 this.stream.sphere();
12654 lineStart: function lineStart() {
12655 this.stream.lineStart();
12657 lineEnd: function lineEnd() {
12658 this.stream.lineEnd();
12660 polygonStart: function polygonStart() {
12661 this.stream.polygonStart();
12663 polygonEnd: function polygonEnd() {
12664 this.stream.polygonEnd();
12668 function fit(projection, fitBounds, object) {
12669 var clip = projection.clipExtent && projection.clipExtent();
12670 projection.scale(150).translate([0, 0]);
12671 if (clip != null) projection.clipExtent(null);
12672 d3_geoStream(object, projection.stream(boundsStream));
12673 fitBounds(boundsStream.result());
12674 if (clip != null) projection.clipExtent(clip);
12678 function fitExtent(projection, extent, object) {
12679 return fit(projection, function (b) {
12680 var w = extent[1][0] - extent[0][0],
12681 h = extent[1][1] - extent[0][1],
12682 k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
12683 x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
12684 y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
12685 projection.scale(150 * k).translate([x, y]);
12688 function fitSize(projection, size, object) {
12689 return fitExtent(projection, [[0, 0], size], object);
12691 function fitWidth(projection, width, object) {
12692 return fit(projection, function (b) {
12694 k = w / (b[1][0] - b[0][0]),
12695 x = (w - k * (b[1][0] + b[0][0])) / 2,
12697 projection.scale(150 * k).translate([x, y]);
12700 function fitHeight(projection, height, object) {
12701 return fit(projection, function (b) {
12703 k = h / (b[1][1] - b[0][1]),
12705 y = (h - k * (b[1][1] + b[0][1])) / 2;
12706 projection.scale(150 * k).translate([x, y]);
12711 // maximum depth of subdivision
12712 cosMinDistance = cos(30 * radians); // cos(minimum angular distance)
12714 function resample (project, delta2) {
12715 return +delta2 ? resample$1(project, delta2) : resampleNone(project);
12718 function resampleNone(project) {
12719 return transformer$1({
12720 point: function point(x, y) {
12722 this.stream.point(x[0], x[1]);
12727 function resample$1(project, delta2) {
12728 function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
12731 d2 = dx * dx + dy * dy;
12733 if (d2 > 4 * delta2 && depth--) {
12737 m = sqrt(a * a + b * b + c * c),
12738 phi2 = asin(c /= m),
12739 lambda2 = abs$2(abs$2(c) - 1) < epsilon$1 || abs$2(lambda0 - lambda1) < epsilon$1 ? (lambda0 + lambda1) / 2 : atan2(b, a),
12740 p = project(lambda2, phi2),
12745 dz = dy * dx2 - dx * dy2;
12747 if (dz * dz / d2 > delta2 // perpendicular projected distance
12748 || abs$2((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
12749 || a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) {
12750 // angular distance
12751 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
12752 stream.point(x2, y2);
12753 resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
12758 return function (stream) {
12759 var lambda00, x00, y00, a00, b00, c00, // first point
12760 lambda0, x0, y0, a0, b0, c0; // previous point
12762 var resampleStream = {
12764 lineStart: lineStart,
12766 polygonStart: function polygonStart() {
12767 stream.polygonStart();
12768 resampleStream.lineStart = ringStart;
12770 polygonEnd: function polygonEnd() {
12771 stream.polygonEnd();
12772 resampleStream.lineStart = lineStart;
12776 function point(x, y) {
12778 stream.point(x[0], x[1]);
12781 function lineStart() {
12783 resampleStream.point = linePoint;
12784 stream.lineStart();
12787 function linePoint(lambda, phi) {
12788 var c = cartesian([lambda, phi]),
12789 p = project(lambda, phi);
12790 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
12791 stream.point(x0, y0);
12794 function lineEnd() {
12795 resampleStream.point = point;
12799 function ringStart() {
12801 resampleStream.point = ringPoint;
12802 resampleStream.lineEnd = ringEnd;
12805 function ringPoint(lambda, phi) {
12806 linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
12807 resampleStream.point = linePoint;
12810 function ringEnd() {
12811 resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
12812 resampleStream.lineEnd = lineEnd;
12816 return resampleStream;
12820 var transformRadians = transformer$1({
12821 point: function point(x, y) {
12822 this.stream.point(x * radians, y * radians);
12826 function transformRotate(rotate) {
12827 return transformer$1({
12828 point: function point(x, y) {
12829 var r = rotate(x, y);
12830 return this.stream.point(r[0], r[1]);
12835 function scaleTranslate(k, dx, dy, sx, sy) {
12836 function transform(x, y) {
12839 return [dx + k * x, dy - k * y];
12842 transform.invert = function (x, y) {
12843 return [(x - dx) / k * sx, (dy - y) / k * sy];
12849 function scaleTranslateRotate(k, dx, dy, sx, sy, alpha) {
12850 if (!alpha) return scaleTranslate(k, dx, dy, sx, sy);
12851 var cosAlpha = cos(alpha),
12852 sinAlpha = sin(alpha),
12857 ci = (sinAlpha * dy - cosAlpha * dx) / k,
12858 fi = (sinAlpha * dx + cosAlpha * dy) / k;
12860 function transform(x, y) {
12863 return [a * x - b * y + dx, dy - b * x - a * y];
12866 transform.invert = function (x, y) {
12867 return [sx * (ai * x - bi * y + ci), sy * (fi - bi * x - ai * y)];
12873 function projection(project) {
12874 return projectionMutator(function () {
12878 function projectionMutator(projectAt) {
12894 // post-rotate angle
12900 preclip = clipAntimeridian,
12906 postclip = identity$4,
12907 // post-clip extent
12912 projectRotateTransform,
12916 function projection(point) {
12917 return projectRotateTransform(point[0] * radians, point[1] * radians);
12920 function invert(point) {
12921 point = projectRotateTransform.invert(point[0], point[1]);
12922 return point && [point[0] * degrees$1, point[1] * degrees$1];
12925 projection.stream = function (stream) {
12926 return cache && cacheStream === stream ? cache : cache = transformRadians(transformRotate(rotate)(preclip(projectResample(postclip(cacheStream = stream)))));
12929 projection.preclip = function (_) {
12930 return arguments.length ? (preclip = _, theta = undefined, reset()) : preclip;
12933 projection.postclip = function (_) {
12934 return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
12937 projection.clipAngle = function (_) {
12938 return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
12941 projection.clipExtent = function (_) {
12942 return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
12945 projection.scale = function (_) {
12946 return arguments.length ? (k = +_, recenter()) : k;
12949 projection.translate = function (_) {
12950 return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
12953 projection.center = function (_) {
12954 return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
12957 projection.rotate = function (_) {
12958 return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
12961 projection.angle = function (_) {
12962 return arguments.length ? (alpha = _ % 360 * radians, recenter()) : alpha * degrees$1;
12965 projection.reflectX = function (_) {
12966 return arguments.length ? (sx = _ ? -1 : 1, recenter()) : sx < 0;
12969 projection.reflectY = function (_) {
12970 return arguments.length ? (sy = _ ? -1 : 1, recenter()) : sy < 0;
12973 projection.precision = function (_) {
12974 return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt(delta2);
12977 projection.fitExtent = function (extent, object) {
12978 return fitExtent(projection, extent, object);
12981 projection.fitSize = function (size, object) {
12982 return fitSize(projection, size, object);
12985 projection.fitWidth = function (width, object) {
12986 return fitWidth(projection, width, object);
12989 projection.fitHeight = function (height, object) {
12990 return fitHeight(projection, height, object);
12993 function recenter() {
12994 var center = scaleTranslateRotate(k, 0, 0, sx, sy, alpha).apply(null, project(lambda, phi)),
12995 transform = scaleTranslateRotate(k, x - center[0], y - center[1], sx, sy, alpha);
12996 rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma);
12997 projectTransform = compose(project, transform);
12998 projectRotateTransform = compose(rotate, projectTransform);
12999 projectResample = resample(projectTransform, delta2);
13004 cache = cacheStream = null;
13008 return function () {
13009 project = projectAt.apply(this, arguments);
13010 projection.invert = project.invert && invert;
13015 function mercatorRaw(lambda, phi) {
13016 return [lambda, log$1(tan((halfPi + phi) / 2))];
13019 mercatorRaw.invert = function (x, y) {
13020 return [x, 2 * atan(exp$2(y)) - halfPi];
13023 function mercator () {
13024 return mercatorProjection(mercatorRaw).scale(961 / tau);
13026 function mercatorProjection(project) {
13027 var m = projection(project),
13030 translate = m.translate,
13031 clipExtent = m.clipExtent,
13037 m.scale = function (_) {
13038 return arguments.length ? (scale(_), reclip()) : scale();
13041 m.translate = function (_) {
13042 return arguments.length ? (translate(_), reclip()) : translate();
13045 m.center = function (_) {
13046 return arguments.length ? (center(_), reclip()) : center();
13049 m.clipExtent = function (_) {
13050 return arguments.length ? (_ == null ? x0 = y0 = x1 = y1 = null : (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reclip()) : x0 == null ? null : [[x0, y0], [x1, y1]];
13053 function reclip() {
13054 var k = pi * scale(),
13055 t = m(rotation(m.rotate()).invert([0, 0]));
13056 return clipExtent(x0 == null ? [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]] : project === mercatorRaw ? [[Math.max(t[0] - k, x0), y0], [Math.min(t[0] + k, x1), y1]] : [[x0, Math.max(t[1] - k, y0)], [x1, Math.min(t[1] + k, y1)]]);
13062 function d3_geoIdentity () {
13068 // scale, translate and reflect
13080 transform = transformer$1({
13081 point: function point(x, y) {
13082 var p = projection([x, y]);
13083 this.stream.point(p[0], p[1]);
13086 postclip = identity$4,
13093 cache = cacheStream = null;
13097 function projection(p) {
13102 var t = y * ca - x * sa;
13103 x = x * ca + y * sa;
13107 return [x + tx, y + ty];
13110 projection.invert = function (p) {
13115 var t = y * ca + x * sa;
13116 x = x * ca - y * sa;
13120 return [x / kx, y / ky];
13123 projection.stream = function (stream) {
13124 return cache && cacheStream === stream ? cache : cache = transform(postclip(cacheStream = stream));
13127 projection.postclip = function (_) {
13128 return arguments.length ? (postclip = _, x0 = y0 = x1 = y1 = null, reset()) : postclip;
13131 projection.clipExtent = function (_) {
13132 return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$4) : clipRectangle(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
13135 projection.scale = function (_) {
13136 return arguments.length ? (k = +_, reset()) : k;
13139 projection.translate = function (_) {
13140 return arguments.length ? (tx = +_[0], ty = +_[1], reset()) : [tx, ty];
13143 projection.angle = function (_) {
13144 return arguments.length ? (alpha = _ % 360 * radians, sa = sin(alpha), ca = cos(alpha), reset()) : alpha * degrees$1;
13147 projection.reflectX = function (_) {
13148 return arguments.length ? (sx = _ ? -1 : 1, reset()) : sx < 0;
13151 projection.reflectY = function (_) {
13152 return arguments.length ? (sy = _ ? -1 : 1, reset()) : sy < 0;
13155 projection.fitExtent = function (extent, object) {
13156 return fitExtent(projection, extent, object);
13159 projection.fitSize = function (size, object) {
13160 return fitSize(projection, size, object);
13163 projection.fitWidth = function (width, object) {
13164 return fitWidth(projection, width, object);
13167 projection.fitHeight = function (height, object) {
13168 return fitHeight(projection, height, object);
13175 var TAU = 2 * Math.PI;
13176 var EQUATORIAL_RADIUS = 6356752.314245179;
13177 var POLAR_RADIUS = 6378137.0;
13178 function geoLatToMeters(dLat) {
13179 return dLat * (TAU * POLAR_RADIUS / 360);
13181 function geoLonToMeters(dLon, atLat) {
13182 return Math.abs(atLat) >= 90 ? 0 : dLon * (TAU * EQUATORIAL_RADIUS / 360) * Math.abs(Math.cos(atLat * (Math.PI / 180)));
13184 function geoMetersToLat(m) {
13185 return m / (TAU * POLAR_RADIUS / 360);
13187 function geoMetersToLon(m, atLat) {
13188 return Math.abs(atLat) >= 90 ? 0 : m / (TAU * EQUATORIAL_RADIUS / 360) / Math.abs(Math.cos(atLat * (Math.PI / 180)));
13190 function geoMetersToOffset(meters, tileSize) {
13191 tileSize = tileSize || 256;
13192 return [meters[0] * tileSize / (TAU * EQUATORIAL_RADIUS), -meters[1] * tileSize / (TAU * POLAR_RADIUS)];
13194 function geoOffsetToMeters(offset, tileSize) {
13195 tileSize = tileSize || 256;
13196 return [offset[0] * TAU * EQUATORIAL_RADIUS / tileSize, -offset[1] * TAU * POLAR_RADIUS / tileSize];
13197 } // Equirectangular approximation of spherical distances on Earth
13199 function geoSphericalDistance(a, b) {
13200 var x = geoLonToMeters(a[0] - b[0], (a[1] + b[1]) / 2);
13201 var y = geoLatToMeters(a[1] - b[1]);
13202 return Math.sqrt(x * x + y * y);
13205 function geoScaleToZoom(k, tileSize) {
13206 tileSize = tileSize || 256;
13207 var log2ts = Math.log(tileSize) * Math.LOG2E;
13208 return Math.log(k * TAU) / Math.LN2 - log2ts;
13211 function geoZoomToScale(z, tileSize) {
13212 tileSize = tileSize || 256;
13213 return tileSize * Math.pow(2, z) / TAU;
13214 } // returns info about the node from `nodes` closest to the given `point`
13216 function geoSphericalClosestNode(nodes, point) {
13217 var minDistance = Infinity,
13221 for (var i in nodes) {
13222 distance = geoSphericalDistance(nodes[i].loc, point);
13224 if (distance < minDistance) {
13225 minDistance = distance;
13230 if (indexOfMin !== undefined) {
13233 distance: minDistance,
13234 node: nodes[indexOfMin]
13241 function geoExtent(min, max) {
13242 if (!(this instanceof geoExtent)) {
13243 return new geoExtent(min, max);
13244 } else if (min instanceof geoExtent) {
13246 } else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
13250 this[0] = min || [Infinity, Infinity];
13251 this[1] = max || min || [-Infinity, -Infinity];
13254 geoExtent.prototype = new Array(2);
13255 Object.assign(geoExtent.prototype, {
13256 equals: function equals(obj) {
13257 return this[0][0] === obj[0][0] && this[0][1] === obj[0][1] && this[1][0] === obj[1][0] && this[1][1] === obj[1][1];
13259 extend: function extend(obj) {
13260 if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13261 return geoExtent([Math.min(obj[0][0], this[0][0]), Math.min(obj[0][1], this[0][1])], [Math.max(obj[1][0], this[1][0]), Math.max(obj[1][1], this[1][1])]);
13263 _extend: function _extend(extent) {
13264 this[0][0] = Math.min(extent[0][0], this[0][0]);
13265 this[0][1] = Math.min(extent[0][1], this[0][1]);
13266 this[1][0] = Math.max(extent[1][0], this[1][0]);
13267 this[1][1] = Math.max(extent[1][1], this[1][1]);
13269 area: function area() {
13270 return Math.abs((this[1][0] - this[0][0]) * (this[1][1] - this[0][1]));
13272 center: function center() {
13273 return [(this[0][0] + this[1][0]) / 2, (this[0][1] + this[1][1]) / 2];
13275 rectangle: function rectangle() {
13276 return [this[0][0], this[0][1], this[1][0], this[1][1]];
13278 bbox: function bbox() {
13286 polygon: function polygon() {
13287 return [[this[0][0], this[0][1]], [this[0][0], this[1][1]], [this[1][0], this[1][1]], [this[1][0], this[0][1]], [this[0][0], this[0][1]]];
13289 contains: function contains(obj) {
13290 if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13291 return obj[0][0] >= this[0][0] && obj[0][1] >= this[0][1] && obj[1][0] <= this[1][0] && obj[1][1] <= this[1][1];
13293 intersects: function intersects(obj) {
13294 if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13295 return obj[0][0] <= this[1][0] && obj[0][1] <= this[1][1] && obj[1][0] >= this[0][0] && obj[1][1] >= this[0][1];
13297 intersection: function intersection(obj) {
13298 if (!this.intersects(obj)) return new geoExtent();
13299 return new geoExtent([Math.max(obj[0][0], this[0][0]), Math.max(obj[0][1], this[0][1])], [Math.min(obj[1][0], this[1][0]), Math.min(obj[1][1], this[1][1])]);
13301 percentContainedIn: function percentContainedIn(obj) {
13302 if (!(obj instanceof geoExtent)) obj = new geoExtent(obj);
13303 var a1 = this.intersection(obj).area();
13304 var a2 = this.area();
13306 if (a1 === Infinity || a2 === Infinity) {
13308 } else if (a1 === 0 || a2 === 0) {
13309 if (obj.contains(this)) {
13318 padByMeters: function padByMeters(meters) {
13319 var dLat = geoMetersToLat(meters);
13320 var dLon = geoMetersToLon(meters, this.center()[1]);
13321 return geoExtent([this[0][0] - dLon, this[0][1] - dLat], [this[1][0] + dLon, this[1][1] + dLat]);
13323 toParam: function toParam() {
13324 return this.rectangle().join(',');
13329 var $every = arrayIteration.every;
13330 var arrayMethodIsStrict$1 = arrayMethodIsStrict$8;
13332 var STRICT_METHOD$1 = arrayMethodIsStrict$1('every');
13334 // `Array.prototype.every` method
13335 // https://tc39.es/ecma262/#sec-array.prototype.every
13336 $$p({ target: 'Array', proto: true, forced: !STRICT_METHOD$1 }, {
13337 every: function every(callbackfn /* , thisArg */) {
13338 return $every(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
13343 var $reduce = arrayReduce.left;
13344 var arrayMethodIsStrict = arrayMethodIsStrict$8;
13345 var CHROME_VERSION = engineV8Version;
13346 var IS_NODE = engineIsNode;
13348 var STRICT_METHOD = arrayMethodIsStrict('reduce');
13349 // Chrome 80-82 has a critical bug
13350 // https://bugs.chromium.org/p/chromium/issues/detail?id=1049982
13351 var CHROME_BUG = !IS_NODE && CHROME_VERSION > 79 && CHROME_VERSION < 83;
13353 // `Array.prototype.reduce` method
13354 // https://tc39.es/ecma262/#sec-array.prototype.reduce
13355 $$o({ target: 'Array', proto: true, forced: !STRICT_METHOD || CHROME_BUG }, {
13356 reduce: function reduce(callbackfn /* , initialValue */) {
13357 return $reduce(this, callbackfn, arguments.length, arguments.length > 1 ? arguments[1] : undefined);
13361 function d3_polygonArea (polygon) {
13363 n = polygon.length,
13365 b = polygon[n - 1],
13371 area += a[1] * b[0] - a[0] * b[1];
13377 function d3_polygonCentroid (polygon) {
13379 n = polygon.length,
13383 b = polygon[n - 1],
13390 k += c = a[0] * b[1] - b[0] * a[1];
13391 x += (a[0] + b[0]) * c;
13392 y += (a[1] + b[1]) * c;
13395 return k *= 3, [x / k, y / k];
13398 // Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
13399 // the 3D cross product in a quadrant I Cartesian coordinate system (+x is
13400 // right, +y is up). Returns a positive value if ABC is counter-clockwise,
13401 // negative if clockwise, and zero if the points are collinear.
13402 function cross (a, b, c) {
13403 return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
13406 function lexicographicOrder(a, b) {
13407 return a[0] - b[0] || a[1] - b[1];
13408 } // Computes the upper convex hull per the monotone chain algorithm.
13409 // Assumes points.length >= 3, is sorted by x, unique in y.
13410 // Returns an array of indices into points in left-to-right order.
13413 function computeUpperHullIndexes(points) {
13414 var n = points.length,
13419 for (i = 2; i < n; ++i) {
13420 while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) {
13424 indexes[size++] = i;
13427 return indexes.slice(0, size); // remove popped points
13430 function d3_polygonHull (points) {
13431 if ((n = points.length) < 3) return null;
13434 sortedPoints = new Array(n),
13435 flippedPoints = new Array(n);
13437 for (i = 0; i < n; ++i) {
13438 sortedPoints[i] = [+points[i][0], +points[i][1], i];
13441 sortedPoints.sort(lexicographicOrder);
13443 for (i = 0; i < n; ++i) {
13444 flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
13447 var upperIndexes = computeUpperHullIndexes(sortedPoints),
13448 lowerIndexes = computeUpperHullIndexes(flippedPoints); // Construct the hull polygon, removing possible duplicate endpoints.
13450 var skipLeft = lowerIndexes[0] === upperIndexes[0],
13451 skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
13452 hull = []; // Add upper hull in right-to-l order.
13453 // Then add lower hull in left-to-right order.
13455 for (i = upperIndexes.length - 1; i >= 0; --i) {
13456 hull.push(points[sortedPoints[upperIndexes[i]][2]]);
13459 for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) {
13460 hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
13467 function geoVecEqual(a, b, epsilon) {
13469 return Math.abs(a[0] - b[0]) <= epsilon && Math.abs(a[1] - b[1]) <= epsilon;
13471 return a[0] === b[0] && a[1] === b[1];
13473 } // vector addition
13475 function geoVecAdd(a, b) {
13476 return [a[0] + b[0], a[1] + b[1]];
13477 } // vector subtraction
13479 function geoVecSubtract(a, b) {
13480 return [a[0] - b[0], a[1] - b[1]];
13481 } // vector scaling
13483 function geoVecScale(a, mag) {
13484 return [a[0] * mag, a[1] * mag];
13485 } // vector rounding (was: geoRoundCoordinates)
13487 function geoVecFloor(a) {
13488 return [Math.floor(a[0]), Math.floor(a[1])];
13489 } // linear interpolation
13491 function geoVecInterp(a, b, t) {
13492 return [a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t];
13493 } // http://jsperf.com/id-dist-optimization
13495 function geoVecLength(a, b) {
13496 return Math.sqrt(geoVecLengthSquare(a, b));
13497 } // length of vector raised to the power two
13499 function geoVecLengthSquare(a, b) {
13501 var x = a[0] - b[0];
13502 var y = a[1] - b[1];
13503 return x * x + y * y;
13504 } // get a unit vector
13506 function geoVecNormalize(a) {
13507 var length = Math.sqrt(a[0] * a[0] + a[1] * a[1]);
13509 if (length !== 0) {
13510 return geoVecScale(a, 1 / length);
13514 } // Return the counterclockwise angle in the range (-pi, pi)
13515 // between the positive X axis and the line intersecting a and b.
13517 function geoVecAngle(a, b) {
13518 return Math.atan2(b[1] - a[1], b[0] - a[0]);
13521 function geoVecDot(a, b, origin) {
13522 origin = origin || [0, 0];
13523 var p = geoVecSubtract(a, origin);
13524 var q = geoVecSubtract(b, origin);
13525 return p[0] * q[0] + p[1] * q[1];
13526 } // normalized dot product
13528 function geoVecNormalizedDot(a, b, origin) {
13529 origin = origin || [0, 0];
13530 var p = geoVecNormalize(geoVecSubtract(a, origin));
13531 var q = geoVecNormalize(geoVecSubtract(b, origin));
13532 return geoVecDot(p, q);
13533 } // 2D cross product of OA and OB vectors, returns magnitude of Z vector
13534 // Returns a positive value, if OAB makes a counter-clockwise turn,
13535 // negative for clockwise turn, and zero if the points are collinear.
13537 function geoVecCross(a, b, origin) {
13538 origin = origin || [0, 0];
13539 var p = geoVecSubtract(a, origin);
13540 var q = geoVecSubtract(b, origin);
13541 return p[0] * q[1] - p[1] * q[0];
13542 } // find closest orthogonal projection of point onto points array
13544 function geoVecProject(a, points) {
13545 var min = Infinity;
13549 for (var i = 0; i < points.length - 1; i++) {
13551 var s = geoVecSubtract(points[i + 1], o);
13552 var v = geoVecSubtract(a, o);
13553 var proj = geoVecDot(v, s) / geoVecDot(s, s);
13558 } else if (proj > 1) {
13561 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
13564 var dist = geoVecLength(p, a);
13573 if (idx !== undefined) {
13584 // between the positive X axis and the line intersecting a and b.
13586 function geoAngle(a, b, projection) {
13587 return geoVecAngle(projection(a.loc), projection(b.loc));
13589 function geoEdgeEqual(a, b) {
13590 return a[0] === b[0] && a[1] === b[1] || a[0] === b[1] && a[1] === b[0];
13591 } // Rotate all points counterclockwise around a pivot point by given angle
13593 function geoRotate(points, angle, around) {
13594 return points.map(function (point) {
13595 var radial = geoVecSubtract(point, around);
13596 return [radial[0] * Math.cos(angle) - radial[1] * Math.sin(angle) + around[0], radial[0] * Math.sin(angle) + radial[1] * Math.cos(angle) + around[1]];
13598 } // Choose the edge with the minimal distance from `point` to its orthogonal
13599 // projection onto that edge, if such a projection exists, or the distance to
13600 // the closest vertex on that edge. Returns an object with the `index` of the
13601 // chosen edge, the chosen `loc` on that edge, and the `distance` to to it.
13603 function geoChooseEdge(nodes, point, projection, activeID) {
13604 var dist = geoVecLength;
13605 var points = nodes.map(function (n) {
13606 return projection(n.loc);
13608 var ids = nodes.map(function (n) {
13611 var min = Infinity;
13615 for (var i = 0; i < points.length - 1; i++) {
13616 if (ids[i] === activeID || ids[i + 1] === activeID) continue;
13618 var s = geoVecSubtract(points[i + 1], o);
13619 var v = geoVecSubtract(point, o);
13620 var proj = geoVecDot(v, s) / geoVecDot(s, s);
13625 } else if (proj > 1) {
13628 p = [o[0] + proj * s[0], o[1] + proj * s[1]];
13631 var d = dist(p, point);
13636 loc = projection.invert(p);
13640 if (idx !== undefined) {
13649 } // Test active (dragged or drawing) segments against inactive segments
13650 // This is used to test e.g. multipolygon rings that cross
13651 // `activeNodes` is the ring containing the activeID being dragged.
13652 // `inactiveNodes` is the other ring to test against
13654 function geoHasLineIntersections(activeNodes, inactiveNodes, activeID) {
13656 var inactives = [];
13657 var j, k, n1, n2, segment; // gather active segments (only segments in activeNodes that contain the activeID)
13659 for (j = 0; j < activeNodes.length - 1; j++) {
13660 n1 = activeNodes[j];
13661 n2 = activeNodes[j + 1];
13662 segment = [n1.loc, n2.loc];
13664 if (n1.id === activeID || n2.id === activeID) {
13665 actives.push(segment);
13667 } // gather inactive segments
13670 for (j = 0; j < inactiveNodes.length - 1; j++) {
13671 n1 = inactiveNodes[j];
13672 n2 = inactiveNodes[j + 1];
13673 segment = [n1.loc, n2.loc];
13674 inactives.push(segment);
13678 for (j = 0; j < actives.length; j++) {
13679 for (k = 0; k < inactives.length; k++) {
13680 var p = actives[j];
13681 var q = inactives[k];
13682 var hit = geoLineIntersection(p, q);
13691 } // Test active (dragged or drawing) segments against inactive segments
13692 // This is used to test whether a way intersects with itself.
13694 function geoHasSelfIntersections(nodes, activeID) {
13696 var inactives = [];
13697 var j, k; // group active and passive segments along the nodes
13699 for (j = 0; j < nodes.length - 1; j++) {
13701 var n2 = nodes[j + 1];
13702 var segment = [n1.loc, n2.loc];
13704 if (n1.id === activeID || n2.id === activeID) {
13705 actives.push(segment);
13707 inactives.push(segment);
13712 for (j = 0; j < actives.length; j++) {
13713 for (k = 0; k < inactives.length; k++) {
13714 var p = actives[j];
13715 var q = inactives[k]; // skip if segments share an endpoint
13717 if (geoVecEqual(p[1], q[0]) || geoVecEqual(p[0], q[1]) || geoVecEqual(p[0], q[0]) || geoVecEqual(p[1], q[1])) {
13721 var hit = geoLineIntersection(p, q);
13724 var epsilon = 1e-8; // skip if the hit is at the segment's endpoint
13726 if (geoVecEqual(p[1], hit, epsilon) || geoVecEqual(p[0], hit, epsilon) || geoVecEqual(q[1], hit, epsilon) || geoVecEqual(q[0], hit, epsilon)) {
13736 } // Return the intersection point of 2 line segments.
13737 // From https://github.com/pgkelley4/line-segments-intersect
13738 // This uses the vector cross product approach described below:
13739 // http://stackoverflow.com/a/565282/786339
13741 function geoLineIntersection(a, b) {
13742 var p = [a[0][0], a[0][1]];
13743 var p2 = [a[1][0], a[1][1]];
13744 var q = [b[0][0], b[0][1]];
13745 var q2 = [b[1][0], b[1][1]];
13746 var r = geoVecSubtract(p2, p);
13747 var s = geoVecSubtract(q2, q);
13748 var uNumerator = geoVecCross(geoVecSubtract(q, p), r);
13749 var denominator = geoVecCross(r, s);
13751 if (uNumerator && denominator) {
13752 var u = uNumerator / denominator;
13753 var t = geoVecCross(geoVecSubtract(q, p), s) / denominator;
13755 if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
13756 return geoVecInterp(p, p2, t);
13762 function geoPathIntersections(path1, path2) {
13763 var intersections = [];
13765 for (var i = 0; i < path1.length - 1; i++) {
13766 for (var j = 0; j < path2.length - 1; j++) {
13767 var a = [path1[i], path1[i + 1]];
13768 var b = [path2[j], path2[j + 1]];
13769 var hit = geoLineIntersection(a, b);
13772 intersections.push(hit);
13777 return intersections;
13779 function geoPathHasIntersections(path1, path2) {
13780 for (var i = 0; i < path1.length - 1; i++) {
13781 for (var j = 0; j < path2.length - 1; j++) {
13782 var a = [path1[i], path1[i + 1]];
13783 var b = [path2[j], path2[j + 1]];
13784 var hit = geoLineIntersection(a, b);
13793 } // Return whether point is contained in polygon.
13795 // `point` should be a 2-item array of coordinates.
13796 // `polygon` should be an array of 2-item arrays of coordinates.
13798 // From https://github.com/substack/point-in-polygon.
13799 // ray-casting algorithm based on
13800 // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
13803 function geoPointInPolygon(point, polygon) {
13806 var inside = false;
13808 for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
13809 var xi = polygon[i][0];
13810 var yi = polygon[i][1];
13811 var xj = polygon[j][0];
13812 var yj = polygon[j][1];
13813 var intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi;
13814 if (intersect) inside = !inside;
13819 function geoPolygonContainsPolygon(outer, inner) {
13820 return inner.every(function (point) {
13821 return geoPointInPolygon(point, outer);
13824 function geoPolygonIntersectsPolygon(outer, inner, checkSegments) {
13825 function testPoints(outer, inner) {
13826 return inner.some(function (point) {
13827 return geoPointInPolygon(point, outer);
13831 return testPoints(outer, inner) || !!checkSegments && geoPathHasIntersections(outer, inner);
13832 } // http://gis.stackexchange.com/questions/22895/finding-minimum-area-rectangle-for-given-points
13833 // http://gis.stackexchange.com/questions/3739/generalisation-strategies-for-building-outlines/3756#3756
13835 function geoGetSmallestSurroundingRectangle(points) {
13836 var hull = d3_polygonHull(points);
13837 var centroid = d3_polygonCentroid(hull);
13838 var minArea = Infinity;
13839 var ssrExtent = [];
13843 for (var i = 0; i <= hull.length - 1; i++) {
13844 var c2 = i === hull.length - 1 ? hull[0] : hull[i + 1];
13845 var angle = Math.atan2(c2[1] - c1[1], c2[0] - c1[0]);
13846 var poly = geoRotate(hull, -angle, centroid);
13847 var extent = poly.reduce(function (extent, point) {
13848 return extent.extend(geoExtent(point));
13850 var area = extent.area();
13852 if (area < minArea) {
13854 ssrExtent = extent;
13862 poly: geoRotate(ssrExtent.polygon(), ssrAngle, centroid),
13866 function geoPathLength(path) {
13869 for (var i = 0; i < path.length - 1; i++) {
13870 length += geoVecLength(path[i], path[i + 1]);
13874 } // If the given point is at the edge of the padded viewport,
13875 // return a vector that will nudge the viewport in that direction
13877 function geoViewportEdge(point, dimensions) {
13878 var pad = [80, 20, 50, 20]; // top, right, bottom, left
13883 if (point[0] > dimensions[0] - pad[1]) {
13887 if (point[0] < pad[3]) {
13891 if (point[1] > dimensions[1] - pad[2]) {
13895 if (point[1] < pad[0]) {
13907 value: function value() {}
13910 function dispatch$8() {
13911 for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
13912 if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
13916 return new Dispatch(_);
13919 function Dispatch(_) {
13923 function parseTypenames$1(typenames, types) {
13924 return typenames.trim().split(/^|\s+/).map(function (t) {
13926 i = t.indexOf(".");
13927 if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
13928 if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
13936 Dispatch.prototype = dispatch$8.prototype = {
13937 constructor: Dispatch,
13938 on: function on(typename, callback) {
13940 T = parseTypenames$1(typename + "", _),
13943 n = T.length; // If no callback was specified, return the callback of the given type and name.
13945 if (arguments.length < 2) {
13947 if ((t = (typename = T[i]).type) && (t = get$2(_[t], typename.name))) return t;
13951 } // If a type was specified, set the callback for the given type and name.
13952 // Otherwise, if a null callback was specified, remove callbacks of the given name.
13955 if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
13958 if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);else if (callback == null) for (t in _) {
13959 _[t] = set$1(_[t], typename.name, null);
13965 copy: function copy() {
13970 copy[t] = _[t].slice();
13973 return new Dispatch(copy);
13975 call: function call(type, that) {
13976 if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) {
13977 args[i] = arguments[i + 2];
13979 if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13981 for (t = this._[type], i = 0, n = t.length; i < n; ++i) {
13982 t[i].value.apply(that, args);
13985 apply: function apply(type, that, args) {
13986 if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
13988 for (var t = this._[type], i = 0, n = t.length; i < n; ++i) {
13989 t[i].value.apply(that, args);
13994 function get$2(type, name) {
13995 for (var i = 0, n = type.length, c; i < n; ++i) {
13996 if ((c = type[i]).name === name) {
14002 function set$1(type, name, callback) {
14003 for (var i = 0, n = type.length; i < n; ++i) {
14004 if (type[i].name === name) {
14005 type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
14010 if (callback != null) type.push({
14017 var xhtml = "http://www.w3.org/1999/xhtml";
14019 svg: "http://www.w3.org/2000/svg",
14021 xlink: "http://www.w3.org/1999/xlink",
14022 xml: "http://www.w3.org/XML/1998/namespace",
14023 xmlns: "http://www.w3.org/2000/xmlns/"
14026 function namespace (name) {
14027 var prefix = name += "",
14028 i = prefix.indexOf(":");
14029 if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
14030 return namespaces.hasOwnProperty(prefix) ? {
14031 space: namespaces[prefix],
14033 } : name; // eslint-disable-line no-prototype-builtins
14036 function creatorInherit(name) {
14037 return function () {
14038 var document = this.ownerDocument,
14039 uri = this.namespaceURI;
14040 return uri === xhtml && document.documentElement.namespaceURI === xhtml ? document.createElement(name) : document.createElementNS(uri, name);
14044 function creatorFixed(fullname) {
14045 return function () {
14046 return this.ownerDocument.createElementNS(fullname.space, fullname.local);
14050 function creator (name) {
14051 var fullname = namespace(name);
14052 return (fullname.local ? creatorFixed : creatorInherit)(fullname);
14057 function selector (selector) {
14058 return selector == null ? none : function () {
14059 return this.querySelector(selector);
14063 function selection_select (select) {
14064 if (typeof select !== "function") select = selector(select);
14066 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
14067 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
14068 if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
14069 if ("__data__" in node) subnode.__data__ = node.__data__;
14070 subgroup[i] = subnode;
14075 return new Selection$1(subgroups, this._parents);
14078 function array (x) {
14079 return _typeof(x) === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like
14080 : Array.from(x); // Map, Set, iterable, string, or anything else
14087 function selectorAll (selector) {
14088 return selector == null ? empty : function () {
14089 return this.querySelectorAll(selector);
14093 function arrayAll(select) {
14094 return function () {
14095 var group = select.apply(this, arguments);
14096 return group == null ? [] : array(group);
14100 function selection_selectAll (select) {
14101 if (typeof select === "function") select = arrayAll(select);else select = selectorAll(select);
14103 for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
14104 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
14105 if (node = group[i]) {
14106 subgroups.push(select.call(node, node.__data__, i, group));
14107 parents.push(node);
14112 return new Selection$1(subgroups, parents);
14116 var $find = arrayIteration.find;
14117 var addToUnscopables$2 = addToUnscopables$5;
14120 var SKIPS_HOLES$1 = true;
14122 // Shouldn't skip holes
14123 if (FIND in []) Array(1)[FIND](function () { SKIPS_HOLES$1 = false; });
14125 // `Array.prototype.find` method
14126 // https://tc39.es/ecma262/#sec-array.prototype.find
14127 $$n({ target: 'Array', proto: true, forced: SKIPS_HOLES$1 }, {
14128 find: function find(callbackfn /* , that = undefined */) {
14129 return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
14133 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
14134 addToUnscopables$2(FIND);
14136 function matcher (selector) {
14137 return function () {
14138 return this.matches(selector);
14141 function childMatcher(selector) {
14142 return function (node) {
14143 return node.matches(selector);
14147 var find = Array.prototype.find;
14149 function childFind(match) {
14150 return function () {
14151 return find.call(this.children, match);
14155 function childFirst() {
14156 return this.firstElementChild;
14159 function selection_selectChild (match) {
14160 return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
14163 var filter = Array.prototype.filter;
14165 function children() {
14166 return this.children;
14169 function childrenFilter(match) {
14170 return function () {
14171 return filter.call(this.children, match);
14175 function selection_selectChildren (match) {
14176 return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
14179 function selection_filter (match) {
14180 if (typeof match !== "function") match = matcher(match);
14182 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
14183 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
14184 if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
14185 subgroup.push(node);
14190 return new Selection$1(subgroups, this._parents);
14193 function sparse (update) {
14194 return new Array(update.length);
14197 function selection_enter () {
14198 return new Selection$1(this._enter || this._groups.map(sparse), this._parents);
14200 function EnterNode(parent, datum) {
14201 this.ownerDocument = parent.ownerDocument;
14202 this.namespaceURI = parent.namespaceURI;
14204 this._parent = parent;
14205 this.__data__ = datum;
14207 EnterNode.prototype = {
14208 constructor: EnterNode,
14209 appendChild: function appendChild(child) {
14210 return this._parent.insertBefore(child, this._next);
14212 insertBefore: function insertBefore(child, next) {
14213 return this._parent.insertBefore(child, next);
14215 querySelector: function querySelector(selector) {
14216 return this._parent.querySelector(selector);
14218 querySelectorAll: function querySelectorAll(selector) {
14219 return this._parent.querySelectorAll(selector);
14223 function constant$3 (x) {
14224 return function () {
14229 function bindIndex(parent, group, enter, update, exit, data) {
14232 groupLength = group.length,
14233 dataLength = data.length; // Put any non-null nodes that fit into update.
14234 // Put any null nodes into enter.
14235 // Put any remaining data into enter.
14237 for (; i < dataLength; ++i) {
14238 if (node = group[i]) {
14239 node.__data__ = data[i];
14242 enter[i] = new EnterNode(parent, data[i]);
14244 } // Put any non-null nodes that don’t fit into exit.
14247 for (; i < groupLength; ++i) {
14248 if (node = group[i]) {
14254 function bindKey(parent, group, enter, update, exit, data, key) {
14257 nodeByKeyValue = new Map(),
14258 groupLength = group.length,
14259 dataLength = data.length,
14260 keyValues = new Array(groupLength),
14261 keyValue; // Compute the key for each node.
14262 // If multiple nodes have the same key, the duplicates are added to exit.
14264 for (i = 0; i < groupLength; ++i) {
14265 if (node = group[i]) {
14266 keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
14268 if (nodeByKeyValue.has(keyValue)) {
14271 nodeByKeyValue.set(keyValue, node);
14274 } // Compute the key for each datum.
14275 // If there a node associated with this key, join and add it to update.
14276 // If there is not (or the key is a duplicate), add it to enter.
14279 for (i = 0; i < dataLength; ++i) {
14280 keyValue = key.call(parent, data[i], i, data) + "";
14282 if (node = nodeByKeyValue.get(keyValue)) {
14284 node.__data__ = data[i];
14285 nodeByKeyValue["delete"](keyValue);
14287 enter[i] = new EnterNode(parent, data[i]);
14289 } // Add any remaining nodes that were not bound to data to exit.
14292 for (i = 0; i < groupLength; ++i) {
14293 if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) {
14299 function datum(node) {
14300 return node.__data__;
14303 function selection_data (value, key) {
14304 if (!arguments.length) return Array.from(this, datum);
14305 var bind = key ? bindKey : bindIndex,
14306 parents = this._parents,
14307 groups = this._groups;
14308 if (typeof value !== "function") value = constant$3(value);
14310 for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
14311 var parent = parents[j],
14313 groupLength = group.length,
14314 data = array(value.call(parent, parent && parent.__data__, j, parents)),
14315 dataLength = data.length,
14316 enterGroup = enter[j] = new Array(dataLength),
14317 updateGroup = update[j] = new Array(dataLength),
14318 exitGroup = exit[j] = new Array(groupLength);
14319 bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); // Now connect the enter nodes to their following update node, such that
14320 // appendChild can insert the materialized enter node before this node,
14321 // rather than at the end of the parent node.
14323 for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
14324 if (previous = enterGroup[i0]) {
14325 if (i0 >= i1) i1 = i0 + 1;
14327 while (!(next = updateGroup[i1]) && ++i1 < dataLength) {
14330 previous._next = next || null;
14335 update = new Selection$1(update, parents);
14336 update._enter = enter;
14337 update._exit = exit;
14341 function selection_exit () {
14342 return new Selection$1(this._exit || this._groups.map(sparse), this._parents);
14345 function selection_join (onenter, onupdate, onexit) {
14346 var enter = this.enter(),
14348 exit = this.exit();
14349 enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + "");
14350 if (onupdate != null) update = onupdate(update);
14351 if (onexit == null) exit.remove();else onexit(exit);
14352 return enter && update ? enter.merge(update).order() : update;
14355 function selection_merge (selection) {
14356 if (!(selection instanceof Selection$1)) throw new Error("invalid merge");
14358 for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
14359 for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
14360 if (node = group0[i] || group1[i]) {
14366 for (; j < m0; ++j) {
14367 merges[j] = groups0[j];
14370 return new Selection$1(merges, this._parents);
14373 function selection_order () {
14374 for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
14375 for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
14376 if (node = group[i]) {
14377 if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
14386 function selection_sort (compare) {
14387 if (!compare) compare = ascending;
14389 function compareNode(a, b) {
14390 return a && b ? compare(a.__data__, b.__data__) : !a - !b;
14393 for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
14394 for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
14395 if (node = group[i]) {
14396 sortgroup[i] = node;
14400 sortgroup.sort(compareNode);
14403 return new Selection$1(sortgroups, this._parents).order();
14406 function ascending(a, b) {
14407 return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
14410 function selection_call () {
14411 var callback = arguments[0];
14412 arguments[0] = this;
14413 callback.apply(null, arguments);
14417 function selection_nodes () {
14418 return Array.from(this);
14421 function selection_node () {
14422 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
14423 for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
14424 var node = group[i];
14425 if (node) return node;
14432 function selection_size () {
14435 var _iterator = _createForOfIteratorHelper(this),
14439 for (_iterator.s(); !(_step = _iterator.n()).done;) {
14440 var node = _step.value;
14442 } // eslint-disable-line no-unused-vars
14453 function selection_empty () {
14454 return !this.node();
14457 function selection_each (callback) {
14458 for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
14459 for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
14460 if (node = group[i]) callback.call(node, node.__data__, i, group);
14467 function attrRemove$1(name) {
14468 return function () {
14469 this.removeAttribute(name);
14473 function attrRemoveNS$1(fullname) {
14474 return function () {
14475 this.removeAttributeNS(fullname.space, fullname.local);
14479 function attrConstant$1(name, value) {
14480 return function () {
14481 this.setAttribute(name, value);
14485 function attrConstantNS$1(fullname, value) {
14486 return function () {
14487 this.setAttributeNS(fullname.space, fullname.local, value);
14491 function attrFunction$1(name, value) {
14492 return function () {
14493 var v = value.apply(this, arguments);
14494 if (v == null) this.removeAttribute(name);else this.setAttribute(name, v);
14498 function attrFunctionNS$1(fullname, value) {
14499 return function () {
14500 var v = value.apply(this, arguments);
14501 if (v == null) this.removeAttributeNS(fullname.space, fullname.local);else this.setAttributeNS(fullname.space, fullname.local, v);
14505 function selection_attr (name, value) {
14506 var fullname = namespace(name);
14508 if (arguments.length < 2) {
14509 var node = this.node();
14510 return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
14513 return this.each((value == null ? fullname.local ? attrRemoveNS$1 : attrRemove$1 : typeof value === "function" ? fullname.local ? attrFunctionNS$1 : attrFunction$1 : fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, value));
14516 function defaultView (node) {
14517 return node.ownerDocument && node.ownerDocument.defaultView || // node is a Node
14518 node.document && node // node is a Window
14519 || node.defaultView; // node is a Document
14522 function styleRemove$1(name) {
14523 return function () {
14524 this.style.removeProperty(name);
14528 function styleConstant$1(name, value, priority) {
14529 return function () {
14530 this.style.setProperty(name, value, priority);
14534 function styleFunction$1(name, value, priority) {
14535 return function () {
14536 var v = value.apply(this, arguments);
14537 if (v == null) this.style.removeProperty(name);else this.style.setProperty(name, v, priority);
14541 function selection_style (name, value, priority) {
14542 return arguments.length > 1 ? this.each((value == null ? styleRemove$1 : typeof value === "function" ? styleFunction$1 : styleConstant$1)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
14544 function styleValue(node, name) {
14545 return node.style.getPropertyValue(name) || defaultView(node).getComputedStyle(node, null).getPropertyValue(name);
14548 function propertyRemove(name) {
14549 return function () {
14554 function propertyConstant(name, value) {
14555 return function () {
14556 this[name] = value;
14560 function propertyFunction(name, value) {
14561 return function () {
14562 var v = value.apply(this, arguments);
14563 if (v == null) delete this[name];else this[name] = v;
14567 function selection_property (name, value) {
14568 return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
14571 function classArray(string) {
14572 return string.trim().split(/^|\s+/);
14575 function classList(node) {
14576 return node.classList || new ClassList(node);
14579 function ClassList(node) {
14581 this._names = classArray(node.getAttribute("class") || "");
14584 ClassList.prototype = {
14585 add: function add(name) {
14586 var i = this._names.indexOf(name);
14589 this._names.push(name);
14591 this._node.setAttribute("class", this._names.join(" "));
14594 remove: function remove(name) {
14595 var i = this._names.indexOf(name);
14598 this._names.splice(i, 1);
14600 this._node.setAttribute("class", this._names.join(" "));
14603 contains: function contains(name) {
14604 return this._names.indexOf(name) >= 0;
14608 function classedAdd(node, names) {
14609 var list = classList(node),
14614 list.add(names[i]);
14618 function classedRemove(node, names) {
14619 var list = classList(node),
14624 list.remove(names[i]);
14628 function classedTrue(names) {
14629 return function () {
14630 classedAdd(this, names);
14634 function classedFalse(names) {
14635 return function () {
14636 classedRemove(this, names);
14640 function classedFunction(names, value) {
14641 return function () {
14642 (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
14646 function selection_classed (name, value) {
14647 var names = classArray(name + "");
14649 if (arguments.length < 2) {
14650 var list = classList(this.node()),
14655 if (!list.contains(names[i])) return false;
14661 return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
14664 function textRemove() {
14665 this.textContent = "";
14668 function textConstant$1(value) {
14669 return function () {
14670 this.textContent = value;
14674 function textFunction$1(value) {
14675 return function () {
14676 var v = value.apply(this, arguments);
14677 this.textContent = v == null ? "" : v;
14681 function selection_text (value) {
14682 return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction$1 : textConstant$1)(value)) : this.node().textContent;
14685 function htmlRemove() {
14686 this.innerHTML = "";
14689 function htmlConstant(value) {
14690 return function () {
14691 this.innerHTML = value;
14695 function htmlFunction(value) {
14696 return function () {
14697 var v = value.apply(this, arguments);
14698 this.innerHTML = v == null ? "" : v;
14702 function selection_html (value) {
14703 return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
14707 if (this.nextSibling) this.parentNode.appendChild(this);
14710 function selection_raise () {
14711 return this.each(raise);
14715 if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
14718 function selection_lower () {
14719 return this.each(lower);
14722 function selection_append (name) {
14723 var create = typeof name === "function" ? name : creator(name);
14724 return this.select(function () {
14725 return this.appendChild(create.apply(this, arguments));
14729 function constantNull() {
14733 function selection_insert (name, before) {
14734 var create = typeof name === "function" ? name : creator(name),
14735 select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
14736 return this.select(function () {
14737 return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
14741 function remove$7() {
14742 var parent = this.parentNode;
14743 if (parent) parent.removeChild(this);
14746 function selection_remove () {
14747 return this.each(remove$7);
14750 function selection_cloneShallow() {
14751 var clone = this.cloneNode(false),
14752 parent = this.parentNode;
14753 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14756 function selection_cloneDeep() {
14757 var clone = this.cloneNode(true),
14758 parent = this.parentNode;
14759 return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
14762 function selection_clone (deep) {
14763 return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
14766 function selection_datum (value) {
14767 return arguments.length ? this.property("__data__", value) : this.node().__data__;
14770 function contextListener(listener) {
14771 return function (event) {
14772 listener.call(this, event, this.__data__);
14776 function parseTypenames(typenames) {
14777 return typenames.trim().split(/^|\s+/).map(function (t) {
14779 i = t.indexOf(".");
14780 if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
14788 function onRemove(typename) {
14789 return function () {
14790 var on = this.__on;
14793 for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
14794 if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
14795 this.removeEventListener(o.type, o.listener, o.options);
14801 if (++i) on.length = i;else delete this.__on;
14805 function onAdd(typename, value, options) {
14806 return function () {
14807 var on = this.__on,
14809 listener = contextListener(value);
14810 if (on) for (var j = 0, m = on.length; j < m; ++j) {
14811 if ((o = on[j]).type === typename.type && o.name === typename.name) {
14812 this.removeEventListener(o.type, o.listener, o.options);
14813 this.addEventListener(o.type, o.listener = listener, o.options = options);
14818 this.addEventListener(typename.type, listener, options);
14820 type: typename.type,
14821 name: typename.name,
14823 listener: listener,
14826 if (!on) this.__on = [o];else on.push(o);
14830 function selection_on (typename, value, options) {
14831 var typenames = parseTypenames(typename + ""),
14833 n = typenames.length,
14836 if (arguments.length < 2) {
14837 var on = this.node().__on;
14839 if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
14840 for (i = 0, o = on[j]; i < n; ++i) {
14841 if ((t = typenames[i]).type === o.type && t.name === o.name) {
14849 on = value ? onAdd : onRemove;
14851 for (i = 0; i < n; ++i) {
14852 this.each(on(typenames[i], value, options));
14858 function dispatchEvent(node, type, params) {
14859 var window = defaultView(node),
14860 event = window.CustomEvent;
14862 if (typeof event === "function") {
14863 event = new event(type, params);
14865 event = window.document.createEvent("Event");
14866 if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;else event.initEvent(type, false, false);
14869 node.dispatchEvent(event);
14872 function dispatchConstant(type, params) {
14873 return function () {
14874 return dispatchEvent(this, type, params);
14878 function dispatchFunction(type, params) {
14879 return function () {
14880 return dispatchEvent(this, type, params.apply(this, arguments));
14884 function selection_dispatch (type, params) {
14885 return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
14888 var _marked$1 = /*#__PURE__*/regeneratorRuntime.mark(_callee);
14890 function _callee() {
14891 var groups, j, m, group, i, n, node;
14892 return regeneratorRuntime.wrap(function _callee$(_context) {
14894 switch (_context.prev = _context.next) {
14896 groups = this._groups, j = 0, m = groups.length;
14900 _context.next = 13;
14904 group = groups[j], i = 0, n = group.length;
14908 _context.next = 10;
14912 if (!(node = group[i])) {
14932 return _context.stop();
14935 }, _marked$1, this);
14938 var root$1 = [null];
14939 function Selection$1(groups, parents) {
14940 this._groups = groups;
14941 this._parents = parents;
14944 function selection() {
14945 return new Selection$1([[document.documentElement]], root$1);
14948 function selection_selection() {
14952 Selection$1.prototype = selection.prototype = _defineProperty({
14953 constructor: Selection$1,
14954 select: selection_select,
14955 selectAll: selection_selectAll,
14956 selectChild: selection_selectChild,
14957 selectChildren: selection_selectChildren,
14958 filter: selection_filter,
14959 data: selection_data,
14960 enter: selection_enter,
14961 exit: selection_exit,
14962 join: selection_join,
14963 merge: selection_merge,
14964 selection: selection_selection,
14965 order: selection_order,
14966 sort: selection_sort,
14967 call: selection_call,
14968 nodes: selection_nodes,
14969 node: selection_node,
14970 size: selection_size,
14971 empty: selection_empty,
14972 each: selection_each,
14973 attr: selection_attr,
14974 style: selection_style,
14975 property: selection_property,
14976 classed: selection_classed,
14977 text: selection_text,
14978 html: selection_html,
14979 raise: selection_raise,
14980 lower: selection_lower,
14981 append: selection_append,
14982 insert: selection_insert,
14983 remove: selection_remove,
14984 clone: selection_clone,
14985 datum: selection_datum,
14987 dispatch: selection_dispatch
14988 }, Symbol.iterator, _callee);
14990 function select (selector) {
14991 return typeof selector === "string" ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) : new Selection$1([[selector]], root$1);
14994 function sourceEvent (event) {
14997 while (sourceEvent = event.sourceEvent) {
14998 event = sourceEvent;
15004 function pointer (event, node) {
15005 event = sourceEvent(event);
15006 if (node === undefined) node = event.currentTarget;
15009 var svg = node.ownerSVGElement || node;
15011 if (svg.createSVGPoint) {
15012 var point = svg.createSVGPoint();
15013 point.x = event.clientX, point.y = event.clientY;
15014 point = point.matrixTransform(node.getScreenCTM().inverse());
15015 return [point.x, point.y];
15018 if (node.getBoundingClientRect) {
15019 var rect = node.getBoundingClientRect();
15020 return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
15024 return [event.pageX, event.pageY];
15027 function selectAll (selector) {
15028 return typeof selector === "string" ? new Selection$1([document.querySelectorAll(selector)], [document.documentElement]) : new Selection$1([selector == null ? [] : array(selector)], root$1);
15031 function nopropagation$1(event) {
15032 event.stopImmediatePropagation();
15034 function noevent$1 (event) {
15035 event.preventDefault();
15036 event.stopImmediatePropagation();
15039 function dragDisable (view) {
15040 var root = view.document.documentElement,
15041 selection = select(view).on("dragstart.drag", noevent$1, true);
15043 if ("onselectstart" in root) {
15044 selection.on("selectstart.drag", noevent$1, true);
15046 root.__noselect = root.style.MozUserSelect;
15047 root.style.MozUserSelect = "none";
15050 function yesdrag(view, noclick) {
15051 var root = view.document.documentElement,
15052 selection = select(view).on("dragstart.drag", null);
15055 selection.on("click.drag", noevent$1, true);
15056 setTimeout(function () {
15057 selection.on("click.drag", null);
15061 if ("onselectstart" in root) {
15062 selection.on("selectstart.drag", null);
15064 root.style.MozUserSelect = root.__noselect;
15065 delete root.__noselect;
15069 var constant$2 = (function (x) {
15070 return function () {
15075 function DragEvent(type, _ref) {
15076 var sourceEvent = _ref.sourceEvent,
15077 subject = _ref.subject,
15078 target = _ref.target,
15079 identifier = _ref.identifier,
15080 active = _ref.active,
15085 dispatch = _ref.dispatch;
15086 Object.defineProperties(this, {
15093 value: sourceEvent,
15143 DragEvent.prototype.on = function () {
15144 var value = this._.on.apply(this._, arguments);
15146 return value === this._ ? this : value;
15149 function defaultFilter$2(event) {
15150 return !event.ctrlKey && !event.button;
15153 function defaultContainer() {
15154 return this.parentNode;
15157 function defaultSubject(event, d) {
15158 return d == null ? {
15164 function defaultTouchable$1() {
15165 return navigator.maxTouchPoints || "ontouchstart" in this;
15168 function d3_drag () {
15169 var filter = defaultFilter$2,
15170 container = defaultContainer,
15171 subject = defaultSubject,
15172 touchable = defaultTouchable$1,
15174 listeners = dispatch$8("start", "drag", "end"),
15180 clickDistance2 = 0;
15182 function drag(selection) {
15183 selection.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
15186 function mousedowned(event, d) {
15187 if (touchending || !filter.call(this, event, d)) return;
15188 var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
15189 if (!gesture) return;
15190 select(event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
15191 dragDisable(event.view);
15192 nopropagation$1(event);
15193 mousemoving = false;
15194 mousedownx = event.clientX;
15195 mousedowny = event.clientY;
15196 gesture("start", event);
15199 function mousemoved(event) {
15202 if (!mousemoving) {
15203 var dx = event.clientX - mousedownx,
15204 dy = event.clientY - mousedowny;
15205 mousemoving = dx * dx + dy * dy > clickDistance2;
15208 gestures.mouse("drag", event);
15211 function mouseupped(event) {
15212 select(event.view).on("mousemove.drag mouseup.drag", null);
15213 yesdrag(event.view, mousemoving);
15215 gestures.mouse("end", event);
15218 function touchstarted(event, d) {
15219 if (!filter.call(this, event, d)) return;
15220 var touches = event.changedTouches,
15221 c = container.call(this, event, d),
15222 n = touches.length,
15226 for (i = 0; i < n; ++i) {
15227 if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
15228 nopropagation$1(event);
15229 gesture("start", event, touches[i]);
15234 function touchmoved(event) {
15235 var touches = event.changedTouches,
15236 n = touches.length,
15240 for (i = 0; i < n; ++i) {
15241 if (gesture = gestures[touches[i].identifier]) {
15243 gesture("drag", event, touches[i]);
15248 function touchended(event) {
15249 var touches = event.changedTouches,
15250 n = touches.length,
15253 if (touchending) clearTimeout(touchending);
15254 touchending = setTimeout(function () {
15255 touchending = null;
15256 }, 500); // Ghost clicks are delayed!
15258 for (i = 0; i < n; ++i) {
15259 if (gesture = gestures[touches[i].identifier]) {
15260 nopropagation$1(event);
15261 gesture("end", event, touches[i]);
15266 function beforestart(that, container, event, d, identifier, touch) {
15267 var dispatch = listeners.copy(),
15268 p = pointer(touch || event, container),
15272 if ((s = subject.call(that, new DragEvent("beforestart", {
15273 sourceEvent: event,
15275 identifier: identifier,
15282 }), d)) == null) return;
15283 dx = s.x - p[0] || 0;
15284 dy = s.y - p[1] || 0;
15285 return function gesture(type, event, touch) {
15291 gestures[identifier] = gesture, n = active++;
15295 delete gestures[identifier], --active;
15299 p = pointer(touch || event, container), n = active;
15303 dispatch.call(type, that, new DragEvent(type, {
15304 sourceEvent: event,
15307 identifier: identifier,
15318 drag.filter = function (_) {
15319 return arguments.length ? (filter = typeof _ === "function" ? _ : constant$2(!!_), drag) : filter;
15322 drag.container = function (_) {
15323 return arguments.length ? (container = typeof _ === "function" ? _ : constant$2(_), drag) : container;
15326 drag.subject = function (_) {
15327 return arguments.length ? (subject = typeof _ === "function" ? _ : constant$2(_), drag) : subject;
15330 drag.touchable = function (_) {
15331 return arguments.length ? (touchable = typeof _ === "function" ? _ : constant$2(!!_), drag) : touchable;
15334 drag.on = function () {
15335 var value = listeners.on.apply(listeners, arguments);
15336 return value === listeners ? drag : value;
15339 drag.clickDistance = function (_) {
15340 return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
15346 var DESCRIPTORS$3 = descriptors;
15347 var global$3 = global$F;
15348 var isForced$1 = isForced_1;
15349 var inheritIfRequired$1 = inheritIfRequired$4;
15350 var createNonEnumerableProperty = createNonEnumerableProperty$e;
15351 var defineProperty$1 = objectDefineProperty.f;
15352 var getOwnPropertyNames$1 = objectGetOwnPropertyNames.f;
15353 var isRegExp$1 = isRegexp;
15354 var getFlags = regexpFlags$1;
15355 var stickyHelpers = regexpStickyHelpers;
15356 var redefine$2 = redefine$g.exports;
15357 var fails$a = fails$N;
15359 var enforceInternalState = internalState.enforce;
15360 var setSpecies = setSpecies$5;
15361 var wellKnownSymbol$1 = wellKnownSymbol$s;
15362 var UNSUPPORTED_DOT_ALL = regexpUnsupportedDotAll;
15363 var UNSUPPORTED_NCG = regexpUnsupportedNcg;
15365 var MATCH$1 = wellKnownSymbol$1('match');
15366 var NativeRegExp = global$3.RegExp;
15367 var RegExpPrototype = NativeRegExp.prototype;
15368 // TODO: Use only propper RegExpIdentifierName
15369 var IS_NCG = /^\?<[^\s\d!#%&*+<=>@^][^\s!#%&*+<=>@^]*>/;
15373 // "new" should create a new object, old webkit bug
15374 var CORRECT_NEW = new NativeRegExp(re1) !== re1;
15376 var UNSUPPORTED_Y = stickyHelpers.UNSUPPORTED_Y;
15378 var BASE_FORCED = DESCRIPTORS$3 &&
15379 (!CORRECT_NEW || UNSUPPORTED_Y || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG || fails$a(function () {
15380 re2[MATCH$1] = false;
15381 // RegExp constructor can alter flags and IsRegExp works correct with @@match
15382 return NativeRegExp(re1) != re1 || NativeRegExp(re2) == re2 || NativeRegExp(re1, 'i') != '/a/i';
15385 var handleDotAll = function (string) {
15386 var length = string.length;
15389 var brackets = false;
15391 for (; index <= length; index++) {
15392 chr = string.charAt(index);
15393 if (chr === '\\') {
15394 result += chr + string.charAt(++index);
15397 if (!brackets && chr === '.') {
15398 result += '[\\s\\S]';
15402 } else if (chr === ']') {
15409 var handleNCG = function (string) {
15410 var length = string.length;
15415 var brackets = false;
15418 var groupname = '';
15420 for (; index <= length; index++) {
15421 chr = string.charAt(index);
15422 if (chr === '\\') {
15423 chr = chr + string.charAt(++index);
15424 } else if (chr === ']') {
15426 } else if (!brackets) switch (true) {
15431 if (IS_NCG.test(string.slice(index + 1))) {
15438 case chr === '>' && ncg:
15439 if (groupname === '' || has$1(names, groupname)) {
15440 throw new SyntaxError('Invalid capture group name');
15442 names[groupname] = true;
15443 named.push([groupname, groupid]);
15448 if (ncg) groupname += chr;
15449 else result += chr;
15450 } return [result, named];
15453 // `RegExp` constructor
15454 // https://tc39.es/ecma262/#sec-regexp-constructor
15455 if (isForced$1('RegExp', BASE_FORCED)) {
15456 var RegExpWrapper = function RegExp(pattern, flags) {
15457 var thisIsRegExp = this instanceof RegExpWrapper;
15458 var patternIsRegExp = isRegExp$1(pattern);
15459 var flagsAreUndefined = flags === undefined;
15461 var rawPattern, rawFlags, dotAll, sticky, handled, result, state;
15463 if (!thisIsRegExp && patternIsRegExp && pattern.constructor === RegExpWrapper && flagsAreUndefined) {
15468 if (patternIsRegExp && !flagsAreUndefined) pattern = pattern.source;
15469 } else if (pattern instanceof RegExpWrapper) {
15470 if (flagsAreUndefined) flags = getFlags.call(pattern);
15471 pattern = pattern.source;
15474 pattern = pattern === undefined ? '' : String(pattern);
15475 flags = flags === undefined ? '' : String(flags);
15476 rawPattern = pattern;
15478 if (UNSUPPORTED_DOT_ALL && 'dotAll' in re1) {
15479 dotAll = !!flags && flags.indexOf('s') > -1;
15480 if (dotAll) flags = flags.replace(/s/g, '');
15485 if (UNSUPPORTED_Y && 'sticky' in re1) {
15486 sticky = !!flags && flags.indexOf('y') > -1;
15487 if (sticky) flags = flags.replace(/y/g, '');
15490 if (UNSUPPORTED_NCG) {
15491 handled = handleNCG(pattern);
15492 pattern = handled[0];
15493 groups = handled[1];
15496 result = inheritIfRequired$1(
15497 CORRECT_NEW ? new NativeRegExp(pattern, flags) : NativeRegExp(pattern, flags),
15498 thisIsRegExp ? this : RegExpPrototype,
15502 if (dotAll || sticky || groups.length) {
15503 state = enforceInternalState(result);
15505 state.dotAll = true;
15506 state.raw = RegExpWrapper(handleDotAll(pattern), rawFlags);
15508 if (sticky) state.sticky = true;
15509 if (groups.length) state.groups = groups;
15512 if (pattern !== rawPattern) try {
15513 // fails in old engines, but we have no alternatives for unsupported regex syntax
15514 createNonEnumerableProperty(result, 'source', rawPattern === '' ? '(?:)' : rawPattern);
15515 } catch (error) { /* empty */ }
15520 var proxy = function (key) {
15521 key in RegExpWrapper || defineProperty$1(RegExpWrapper, key, {
15522 configurable: true,
15523 get: function () { return NativeRegExp[key]; },
15524 set: function (it) { NativeRegExp[key] = it; }
15528 for (var keys$1 = getOwnPropertyNames$1(NativeRegExp), index$1 = 0; keys$1.length > index$1;) {
15529 proxy(keys$1[index$1++]);
15532 RegExpPrototype.constructor = RegExpWrapper;
15533 RegExpWrapper.prototype = RegExpPrototype;
15534 redefine$2(global$3, 'RegExp', RegExpWrapper);
15537 // https://tc39.es/ecma262/#sec-get-regexp-@@species
15538 setSpecies('RegExp');
15540 function define (constructor, factory, prototype) {
15541 constructor.prototype = factory.prototype = prototype;
15542 prototype.constructor = constructor;
15544 function extend$3(parent, definition) {
15545 var prototype = Object.create(parent.prototype);
15547 for (var key in definition) {
15548 prototype[key] = definition[key];
15554 function Color() {}
15557 var _brighter = 1 / _darker;
15558 var reI = "\\s*([+-]?\\d+)\\s*",
15559 reN = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",
15560 reP = "\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",
15561 reHex = /^#([0-9a-f]{3,8})$/,
15562 reRgbInteger = new RegExp("^rgb\\(" + [reI, reI, reI] + "\\)$"),
15563 reRgbPercent = new RegExp("^rgb\\(" + [reP, reP, reP] + "\\)$"),
15564 reRgbaInteger = new RegExp("^rgba\\(" + [reI, reI, reI, reN] + "\\)$"),
15565 reRgbaPercent = new RegExp("^rgba\\(" + [reP, reP, reP, reN] + "\\)$"),
15566 reHslPercent = new RegExp("^hsl\\(" + [reN, reP, reP] + "\\)$"),
15567 reHslaPercent = new RegExp("^hsla\\(" + [reN, reP, reP, reN] + "\\)$");
15569 aliceblue: 0xf0f8ff,
15570 antiquewhite: 0xfaebd7,
15572 aquamarine: 0x7fffd4,
15577 blanchedalmond: 0xffebcd,
15579 blueviolet: 0x8a2be2,
15581 burlywood: 0xdeb887,
15582 cadetblue: 0x5f9ea0,
15583 chartreuse: 0x7fff00,
15584 chocolate: 0xd2691e,
15586 cornflowerblue: 0x6495ed,
15587 cornsilk: 0xfff8dc,
15590 darkblue: 0x00008b,
15591 darkcyan: 0x008b8b,
15592 darkgoldenrod: 0xb8860b,
15593 darkgray: 0xa9a9a9,
15594 darkgreen: 0x006400,
15595 darkgrey: 0xa9a9a9,
15596 darkkhaki: 0xbdb76b,
15597 darkmagenta: 0x8b008b,
15598 darkolivegreen: 0x556b2f,
15599 darkorange: 0xff8c00,
15600 darkorchid: 0x9932cc,
15602 darksalmon: 0xe9967a,
15603 darkseagreen: 0x8fbc8f,
15604 darkslateblue: 0x483d8b,
15605 darkslategray: 0x2f4f4f,
15606 darkslategrey: 0x2f4f4f,
15607 darkturquoise: 0x00ced1,
15608 darkviolet: 0x9400d3,
15609 deeppink: 0xff1493,
15610 deepskyblue: 0x00bfff,
15613 dodgerblue: 0x1e90ff,
15614 firebrick: 0xb22222,
15615 floralwhite: 0xfffaf0,
15616 forestgreen: 0x228b22,
15618 gainsboro: 0xdcdcdc,
15619 ghostwhite: 0xf8f8ff,
15621 goldenrod: 0xdaa520,
15624 greenyellow: 0xadff2f,
15626 honeydew: 0xf0fff0,
15628 indianred: 0xcd5c5c,
15632 lavender: 0xe6e6fa,
15633 lavenderblush: 0xfff0f5,
15634 lawngreen: 0x7cfc00,
15635 lemonchiffon: 0xfffacd,
15636 lightblue: 0xadd8e6,
15637 lightcoral: 0xf08080,
15638 lightcyan: 0xe0ffff,
15639 lightgoldenrodyellow: 0xfafad2,
15640 lightgray: 0xd3d3d3,
15641 lightgreen: 0x90ee90,
15642 lightgrey: 0xd3d3d3,
15643 lightpink: 0xffb6c1,
15644 lightsalmon: 0xffa07a,
15645 lightseagreen: 0x20b2aa,
15646 lightskyblue: 0x87cefa,
15647 lightslategray: 0x778899,
15648 lightslategrey: 0x778899,
15649 lightsteelblue: 0xb0c4de,
15650 lightyellow: 0xffffe0,
15652 limegreen: 0x32cd32,
15656 mediumaquamarine: 0x66cdaa,
15657 mediumblue: 0x0000cd,
15658 mediumorchid: 0xba55d3,
15659 mediumpurple: 0x9370db,
15660 mediumseagreen: 0x3cb371,
15661 mediumslateblue: 0x7b68ee,
15662 mediumspringgreen: 0x00fa9a,
15663 mediumturquoise: 0x48d1cc,
15664 mediumvioletred: 0xc71585,
15665 midnightblue: 0x191970,
15666 mintcream: 0xf5fffa,
15667 mistyrose: 0xffe4e1,
15668 moccasin: 0xffe4b5,
15669 navajowhite: 0xffdead,
15673 olivedrab: 0x6b8e23,
15675 orangered: 0xff4500,
15677 palegoldenrod: 0xeee8aa,
15678 palegreen: 0x98fb98,
15679 paleturquoise: 0xafeeee,
15680 palevioletred: 0xdb7093,
15681 papayawhip: 0xffefd5,
15682 peachpuff: 0xffdab9,
15686 powderblue: 0xb0e0e6,
15688 rebeccapurple: 0x663399,
15690 rosybrown: 0xbc8f8f,
15691 royalblue: 0x4169e1,
15692 saddlebrown: 0x8b4513,
15694 sandybrown: 0xf4a460,
15695 seagreen: 0x2e8b57,
15696 seashell: 0xfff5ee,
15700 slateblue: 0x6a5acd,
15701 slategray: 0x708090,
15702 slategrey: 0x708090,
15704 springgreen: 0x00ff7f,
15705 steelblue: 0x4682b4,
15710 turquoise: 0x40e0d0,
15714 whitesmoke: 0xf5f5f5,
15716 yellowgreen: 0x9acd32
15718 define(Color, color, {
15719 copy: function copy(channels) {
15720 return Object.assign(new this.constructor(), this, channels);
15722 displayable: function displayable() {
15723 return this.rgb().displayable();
15725 hex: color_formatHex,
15726 // Deprecated! Use color.formatHex.
15727 formatHex: color_formatHex,
15728 formatHsl: color_formatHsl,
15729 formatRgb: color_formatRgb,
15730 toString: color_formatRgb
15733 function color_formatHex() {
15734 return this.rgb().formatHex();
15737 function color_formatHsl() {
15738 return hslConvert(this).formatHsl();
15741 function color_formatRgb() {
15742 return this.rgb().formatRgb();
15745 function color(format) {
15747 format = (format + "").trim().toLowerCase();
15748 return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) // #ff0000
15749 : l === 3 ? new Rgb(m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, (m & 0xf) << 4 | m & 0xf, 1) // #f00
15750 : l === 8 ? rgba(m >> 24 & 0xff, m >> 16 & 0xff, m >> 8 & 0xff, (m & 0xff) / 0xff) // #ff000000
15751 : l === 4 ? rgba(m >> 12 & 0xf | m >> 8 & 0xf0, m >> 8 & 0xf | m >> 4 & 0xf0, m >> 4 & 0xf | m & 0xf0, ((m & 0xf) << 4 | m & 0xf) / 0xff) // #f000
15752 : null // invalid hex
15753 ) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
15754 : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
15755 : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
15756 : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
15757 : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
15758 : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
15759 : named.hasOwnProperty(format) ? rgbn(named[format]) // eslint-disable-line no-prototype-builtins
15760 : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
15764 return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
15767 function rgba(r, g, b, a) {
15768 if (a <= 0) r = g = b = NaN;
15769 return new Rgb(r, g, b, a);
15772 function rgbConvert(o) {
15773 if (!(o instanceof Color)) o = color(o);
15774 if (!o) return new Rgb();
15776 return new Rgb(o.r, o.g, o.b, o.opacity);
15778 function rgb(r, g, b, opacity) {
15779 return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
15781 function Rgb(r, g, b, opacity) {
15785 this.opacity = +opacity;
15787 define(Rgb, rgb, extend$3(Color, {
15788 brighter: function brighter(k) {
15789 k = k == null ? _brighter : Math.pow(_brighter, k);
15790 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15792 darker: function darker(k) {
15793 k = k == null ? _darker : Math.pow(_darker, k);
15794 return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
15796 rgb: function rgb() {
15799 displayable: function displayable() {
15800 return -0.5 <= this.r && this.r < 255.5 && -0.5 <= this.g && this.g < 255.5 && -0.5 <= this.b && this.b < 255.5 && 0 <= this.opacity && this.opacity <= 1;
15802 hex: rgb_formatHex,
15803 // Deprecated! Use color.formatHex.
15804 formatHex: rgb_formatHex,
15805 formatRgb: rgb_formatRgb,
15806 toString: rgb_formatRgb
15809 function rgb_formatHex() {
15810 return "#" + hex$1(this.r) + hex$1(this.g) + hex$1(this.b);
15813 function rgb_formatRgb() {
15814 var a = this.opacity;
15815 a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15816 return (a === 1 ? "rgb(" : "rgba(") + Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", " + Math.max(0, Math.min(255, Math.round(this.b) || 0)) + (a === 1 ? ")" : ", " + a + ")");
15819 function hex$1(value) {
15820 value = Math.max(0, Math.min(255, Math.round(value) || 0));
15821 return (value < 16 ? "0" : "") + value.toString(16);
15824 function hsla(h, s, l, a) {
15825 if (a <= 0) h = s = l = NaN;else if (l <= 0 || l >= 1) h = s = NaN;else if (s <= 0) h = NaN;
15826 return new Hsl(h, s, l, a);
15829 function hslConvert(o) {
15830 if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
15831 if (!(o instanceof Color)) o = color(o);
15832 if (!o) return new Hsl();
15833 if (o instanceof Hsl) return o;
15838 min = Math.min(r, g, b),
15839 max = Math.max(r, g, b),
15842 l = (max + min) / 2;
15845 if (r === max) h = (g - b) / s + (g < b) * 6;else if (g === max) h = (b - r) / s + 2;else h = (r - g) / s + 4;
15846 s /= l < 0.5 ? max + min : 2 - max - min;
15849 s = l > 0 && l < 1 ? 0 : h;
15852 return new Hsl(h, s, l, o.opacity);
15854 function hsl(h, s, l, opacity) {
15855 return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
15858 function Hsl(h, s, l, opacity) {
15862 this.opacity = +opacity;
15865 define(Hsl, hsl, extend$3(Color, {
15866 brighter: function brighter(k) {
15867 k = k == null ? _brighter : Math.pow(_brighter, k);
15868 return new Hsl(this.h, this.s, this.l * k, this.opacity);
15870 darker: function darker(k) {
15871 k = k == null ? _darker : Math.pow(_darker, k);
15872 return new Hsl(this.h, this.s, this.l * k, this.opacity);
15874 rgb: function rgb() {
15875 var h = this.h % 360 + (this.h < 0) * 360,
15876 s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
15878 m2 = l + (l < 0.5 ? l : 1 - l) * s,
15880 return new Rgb(hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), hsl2rgb(h, m1, m2), hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), this.opacity);
15882 displayable: function displayable() {
15883 return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
15885 formatHsl: function formatHsl() {
15886 var a = this.opacity;
15887 a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
15888 return (a === 1 ? "hsl(" : "hsla(") + (this.h || 0) + ", " + (this.s || 0) * 100 + "%, " + (this.l || 0) * 100 + "%" + (a === 1 ? ")" : ", " + a + ")");
15891 /* From FvD 13.37, CSS Color Module Level 3 */
15893 function hsl2rgb(h, m1, m2) {
15894 return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
15897 var constant$1 = (function (x) {
15898 return function () {
15903 function linear$2(a, d) {
15904 return function (t) {
15909 function exponential(a, b, y) {
15910 return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function (t) {
15911 return Math.pow(a + t * b, y);
15914 function gamma(y) {
15915 return (y = +y) === 1 ? nogamma : function (a, b) {
15916 return b - a ? exponential(a, b, y) : constant$1(isNaN(a) ? b : a);
15919 function nogamma(a, b) {
15921 return d ? linear$2(a, d) : constant$1(isNaN(a) ? b : a);
15924 var d3_interpolateRgb = (function rgbGamma(y) {
15925 var color = gamma(y);
15927 function rgb$1(start, end) {
15928 var r = color((start = rgb(start)).r, (end = rgb(end)).r),
15929 g = color(start.g, end.g),
15930 b = color(start.b, end.b),
15931 opacity = nogamma(start.opacity, end.opacity);
15932 return function (t) {
15936 start.opacity = opacity(t);
15941 rgb$1.gamma = rgbGamma;
15945 function numberArray (a, b) {
15947 var n = a ? Math.min(b.length, a.length) : 0,
15950 return function (t) {
15951 for (i = 0; i < n; ++i) {
15952 c[i] = a[i] * (1 - t) + b[i] * t;
15958 function isNumberArray(x) {
15959 return ArrayBuffer.isView(x) && !(x instanceof DataView);
15962 function genericArray(a, b) {
15963 var nb = b ? b.length : 0,
15964 na = a ? Math.min(nb, a.length) : 0,
15969 for (i = 0; i < na; ++i) {
15970 x[i] = interpolate$1(a[i], b[i]);
15973 for (; i < nb; ++i) {
15977 return function (t) {
15978 for (i = 0; i < na; ++i) {
15986 function date (a, b) {
15987 var d = new Date();
15988 return a = +a, b = +b, function (t) {
15989 return d.setTime(a * (1 - t) + b * t), d;
15993 function d3_interpolateNumber (a, b) {
15994 return a = +a, b = +b, function (t) {
15995 return a * (1 - t) + b * t;
15999 function object (a, b) {
16003 if (a === null || _typeof(a) !== "object") a = {};
16004 if (b === null || _typeof(b) !== "object") b = {};
16008 i[k] = interpolate$1(a[k], b[k]);
16014 return function (t) {
16023 var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,
16024 reB = new RegExp(reA.source, "g");
16027 return function () {
16033 return function (t) {
16038 function interpolateString (a, b) {
16039 var bi = reA.lastIndex = reB.lastIndex = 0,
16040 // scan index for next number in b
16042 // current match in a
16044 // current match in b
16046 // string preceding current number in b, if any
16050 // string constants and placeholders
16051 q = []; // number interpolators
16052 // Coerce inputs to strings.
16054 a = a + "", b = b + ""; // Interpolate pairs of numbers in a & b.
16056 while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
16057 if ((bs = bm.index) > bi) {
16058 // a string precedes the next number in b
16059 bs = b.slice(bi, bs);
16060 if (s[i]) s[i] += bs; // coalesce with previous string
16064 if ((am = am[0]) === (bm = bm[0])) {
16065 // numbers in a & b match
16066 if (s[i]) s[i] += bm; // coalesce with previous string
16069 // interpolate non-matching numbers
16073 x: d3_interpolateNumber(am, bm)
16077 bi = reB.lastIndex;
16078 } // Add remains of b.
16081 if (bi < b.length) {
16083 if (s[i]) s[i] += bs; // coalesce with previous string
16085 } // Special optimization for only a single match.
16086 // Otherwise, interpolate each of the numbers and rejoin the string.
16089 return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function (t) {
16090 for (var i = 0, o; i < b; ++i) {
16091 s[(o = q[i]).i] = o.x(t);
16098 function interpolate$1 (a, b) {
16099 var t = _typeof(b),
16102 return b == null || t === "boolean" ? constant$1(b) : (t === "number" ? d3_interpolateNumber : t === "string" ? (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString : b instanceof color ? d3_interpolateRgb : b instanceof Date ? date : isNumberArray(b) ? numberArray : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object : d3_interpolateNumber)(a, b);
16105 function interpolateRound (a, b) {
16106 return a = +a, b = +b, function (t) {
16107 return Math.round(a * (1 - t) + b * t);
16111 var degrees = 180 / Math.PI;
16120 function decompose (a, b, c, d, e, f) {
16121 var scaleX, scaleY, skewX;
16122 if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
16123 if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
16124 if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
16125 if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
16129 rotate: Math.atan2(b, a) * degrees,
16130 skewX: Math.atan(skewX) * degrees,
16137 /* eslint-disable no-undef */
16139 function parseCss(value) {
16140 var m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
16141 return m.isIdentity ? identity$3 : decompose(m.a, m.b, m.c, m.d, m.e, m.f);
16143 function parseSvg(value) {
16144 if (value == null) return identity$3;
16145 if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
16146 svgNode.setAttribute("transform", value);
16147 if (!(value = svgNode.transform.baseVal.consolidate())) return identity$3;
16148 value = value.matrix;
16149 return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
16152 function interpolateTransform(parse, pxComma, pxParen, degParen) {
16154 return s.length ? s.pop() + " " : "";
16157 function translate(xa, ya, xb, yb, s, q) {
16158 if (xa !== xb || ya !== yb) {
16159 var i = s.push("translate(", null, pxComma, null, pxParen);
16162 x: d3_interpolateNumber(xa, xb)
16165 x: d3_interpolateNumber(ya, yb)
16167 } else if (xb || yb) {
16168 s.push("translate(" + xb + pxComma + yb + pxParen);
16172 function rotate(a, b, s, q) {
16174 if (a - b > 180) b += 360;else if (b - a > 180) a += 360; // shortest path
16177 i: s.push(pop(s) + "rotate(", null, degParen) - 2,
16178 x: d3_interpolateNumber(a, b)
16181 s.push(pop(s) + "rotate(" + b + degParen);
16185 function skewX(a, b, s, q) {
16188 i: s.push(pop(s) + "skewX(", null, degParen) - 2,
16189 x: d3_interpolateNumber(a, b)
16192 s.push(pop(s) + "skewX(" + b + degParen);
16196 function scale(xa, ya, xb, yb, s, q) {
16197 if (xa !== xb || ya !== yb) {
16198 var i = s.push(pop(s) + "scale(", null, ",", null, ")");
16201 x: d3_interpolateNumber(xa, xb)
16204 x: d3_interpolateNumber(ya, yb)
16206 } else if (xb !== 1 || yb !== 1) {
16207 s.push(pop(s) + "scale(" + xb + "," + yb + ")");
16211 return function (a, b) {
16213 // string constants and placeholders
16214 q = []; // number interpolators
16216 a = parse(a), b = parse(b);
16217 translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
16218 rotate(a.rotate, b.rotate, s, q);
16219 skewX(a.skewX, b.skewX, s, q);
16220 scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
16221 a = b = null; // gc
16223 return function (t) {
16229 s[(o = q[i]).i] = o.x(t);
16237 var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
16238 var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
16240 var epsilon2 = 1e-12;
16243 return ((x = Math.exp(x)) + 1 / x) / 2;
16247 return ((x = Math.exp(x)) - 1 / x) / 2;
16251 return ((x = Math.exp(2 * x)) - 1) / (x + 1);
16254 var interpolateZoom = (function zoomRho(rho, rho2, rho4) {
16255 // p0 = [ux0, uy0, w0]
16256 // p1 = [ux1, uy1, w1]
16257 function zoom(p0, p1) {
16266 d2 = dx * dx + dy * dy,
16268 S; // Special case for u0 ≅ u1.
16270 if (d2 < epsilon2) {
16271 S = Math.log(w1 / w0) / rho;
16273 i = function i(t) {
16274 return [ux0 + t * dx, uy0 + t * dy, w0 * Math.exp(rho * t * S)];
16278 var d1 = Math.sqrt(d2),
16279 b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
16280 b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
16281 r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
16282 r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
16283 S = (r1 - r0) / rho;
16285 i = function i(t) {
16288 u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
16289 return [ux0 + u * dx, uy0 + u * dy, w0 * coshr0 / cosh(rho * s + r0)];
16293 i.duration = S * 1000 * rho / Math.SQRT2;
16297 zoom.rho = function (_) {
16298 var _1 = Math.max(1e-3, +_),
16302 return zoomRho(_1, _2, _4);
16306 })(Math.SQRT2, 2, 4);
16308 function d3_quantize (interpolator, n) {
16309 var samples = new Array(n);
16311 for (var i = 0; i < n; ++i) {
16312 samples[i] = interpolator(i / (n - 1));
16319 var bind$2 = functionBind;
16321 // `Function.prototype.bind` method
16322 // https://tc39.es/ecma262/#sec-function.prototype.bind
16323 $$m({ target: 'Function', proto: true }, {
16328 // is an animation frame pending?
16330 // is a timeout pending?
16332 // are any timers active?
16334 // how frequently we check for clock skew
16340 clock = (typeof performance === "undefined" ? "undefined" : _typeof(performance)) === "object" && performance.now ? performance : Date,
16341 setFrame = (typeof window === "undefined" ? "undefined" : _typeof(window)) === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function (f) {
16345 return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
16348 function clearNow() {
16353 this._call = this._time = this._next = null;
16355 Timer.prototype = timer.prototype = {
16356 constructor: Timer,
16357 restart: function restart(callback, delay, time) {
16358 if (typeof callback !== "function") throw new TypeError("callback is not a function");
16359 time = (time == null ? now$1() : +time) + (delay == null ? 0 : +delay);
16361 if (!this._next && taskTail !== this) {
16362 if (taskTail) taskTail._next = this;else taskHead = this;
16366 this._call = callback;
16370 stop: function stop() {
16373 this._time = Infinity;
16378 function timer(callback, delay, time) {
16379 var t = new Timer();
16380 t.restart(callback, delay, time);
16383 function timerFlush() {
16384 now$1(); // Get the current time, if not already set.
16386 ++frame; // Pretend we’ve set an alarm, if we haven’t already.
16392 if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
16400 clockNow = (clockLast = clock.now()) + clockSkew;
16401 frame = timeout = 0;
16413 var now = clock.now(),
16414 delay = now - clockLast;
16415 if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
16426 if (time > t1._time) time = t1._time;
16427 t0 = t1, t1 = t1._next;
16429 t2 = t1._next, t1._next = null;
16430 t1 = t0 ? t0._next = t2 : taskHead = t2;
16438 function sleep(time) {
16439 if (frame) return; // Soonest alarm already set, or will be.
16441 if (timeout) timeout = clearTimeout(timeout);
16442 var delay = time - clockNow; // Strictly less than if we recomputed clockNow.
16445 if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
16446 if (interval) interval = clearInterval(interval);
16448 if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
16449 frame = 1, setFrame(wake);
16453 function d3_timeout (callback, delay, time) {
16454 var t = new Timer();
16455 delay = delay == null ? 0 : +delay;
16456 t.restart(function (elapsed) {
16458 callback(elapsed + delay);
16463 var emptyOn = dispatch$8("start", "end", "cancel", "interrupt");
16464 var emptyTween = [];
16472 function schedule (node, name, id, index, group, timing) {
16473 var schedules = node.__transition;
16474 if (!schedules) node.__transition = {};else if (id in schedules) return;
16475 create$3(node, id, {
16478 // For context during callback.
16480 // For context during callback.
16484 delay: timing.delay,
16485 duration: timing.duration,
16491 function init(node, id) {
16492 var schedule = get$1(node, id);
16493 if (schedule.state > CREATED) throw new Error("too late; already scheduled");
16496 function set(node, id) {
16497 var schedule = get$1(node, id);
16498 if (schedule.state > STARTED) throw new Error("too late; already running");
16501 function get$1(node, id) {
16502 var schedule = node.__transition;
16503 if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
16507 function create$3(node, id, self) {
16508 var schedules = node.__transition,
16509 tween; // Initialize the self timer when the transition is created.
16510 // Note the actual delay is not known until the first callback!
16512 schedules[id] = self;
16513 self.timer = timer(schedule, 0, self.time);
16515 function schedule(elapsed) {
16516 self.state = SCHEDULED;
16517 self.timer.restart(start, self.delay, self.time); // If the elapsed delay is less than our first sleep, start immediately.
16519 if (self.delay <= elapsed) start(elapsed - self.delay);
16522 function start(elapsed) {
16523 var i, j, n, o; // If the state is not SCHEDULED, then we previously errored on start.
16525 if (self.state !== SCHEDULED) return stop();
16527 for (i in schedules) {
16529 if (o.name !== self.name) continue; // While this element already has a starting transition during this frame,
16530 // defer starting an interrupting transition until that transition has a
16531 // chance to tick (and possibly end); see d3/d3-transition#54!
16533 if (o.state === STARTED) return d3_timeout(start); // Interrupt the active transition, if any.
16535 if (o.state === RUNNING) {
16538 o.on.call("interrupt", node, node.__data__, o.index, o.group);
16539 delete schedules[i];
16540 } // Cancel any pre-empted transitions.
16541 else if (+i < id) {
16544 o.on.call("cancel", node, node.__data__, o.index, o.group);
16545 delete schedules[i];
16547 } // Defer the first tick to end of the current frame; see d3/d3#1576.
16548 // Note the transition may be canceled after start and before the first tick!
16549 // Note this must be scheduled before the start event; see d3/d3-transition#16!
16550 // Assuming this is successful, subsequent callbacks go straight to tick.
16553 d3_timeout(function () {
16554 if (self.state === STARTED) {
16555 self.state = RUNNING;
16556 self.timer.restart(tick, self.delay, self.time);
16559 }); // Dispatch the start event.
16560 // Note this must be done before the tween are initialized.
16562 self.state = STARTING;
16563 self.on.call("start", node, node.__data__, self.index, self.group);
16564 if (self.state !== STARTING) return; // interrupted
16566 self.state = STARTED; // Initialize the tween, deleting null tween.
16568 tween = new Array(n = self.tween.length);
16570 for (i = 0, j = -1; i < n; ++i) {
16571 if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
16576 tween.length = j + 1;
16579 function tick(elapsed) {
16580 var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = ENDING, 1),
16585 tween[i].call(node, t);
16586 } // Dispatch the end event.
16589 if (self.state === ENDING) {
16590 self.on.call("end", node, node.__data__, self.index, self.group);
16596 self.state = ENDED;
16598 delete schedules[id];
16600 for (var i in schedules) {
16602 } // eslint-disable-line no-unused-vars
16605 delete node.__transition;
16609 function interrupt (node, name) {
16610 var schedules = node.__transition,
16615 if (!schedules) return;
16616 name = name == null ? null : name + "";
16618 for (i in schedules) {
16619 if ((schedule = schedules[i]).name !== name) {
16624 active = schedule.state > STARTING && schedule.state < ENDING;
16625 schedule.state = ENDED;
16626 schedule.timer.stop();
16627 schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
16628 delete schedules[i];
16631 if (empty) delete node.__transition;
16634 function selection_interrupt (name) {
16635 return this.each(function () {
16636 interrupt(this, name);
16640 function tweenRemove(id, name) {
16641 var tween0, tween1;
16642 return function () {
16643 var schedule = set(this, id),
16644 tween = schedule.tween; // If this node shared tween with the previous node,
16645 // just assign the updated shared tween and we’re done!
16646 // Otherwise, copy-on-write.
16648 if (tween !== tween0) {
16649 tween1 = tween0 = tween;
16651 for (var i = 0, n = tween1.length; i < n; ++i) {
16652 if (tween1[i].name === name) {
16653 tween1 = tween1.slice();
16654 tween1.splice(i, 1);
16660 schedule.tween = tween1;
16664 function tweenFunction(id, name, value) {
16665 var tween0, tween1;
16666 if (typeof value !== "function") throw new Error();
16667 return function () {
16668 var schedule = set(this, id),
16669 tween = schedule.tween; // If this node shared tween with the previous node,
16670 // just assign the updated shared tween and we’re done!
16671 // Otherwise, copy-on-write.
16673 if (tween !== tween0) {
16674 tween1 = (tween0 = tween).slice();
16679 }, i = 0, n = tween1.length; i < n; ++i) {
16680 if (tween1[i].name === name) {
16686 if (i === n) tween1.push(t);
16689 schedule.tween = tween1;
16693 function transition_tween (name, value) {
16697 if (arguments.length < 2) {
16698 var tween = get$1(this.node(), id).tween;
16700 for (var i = 0, n = tween.length, t; i < n; ++i) {
16701 if ((t = tween[i]).name === name) {
16709 return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
16711 function tweenValue(transition, name, value) {
16712 var id = transition._id;
16713 transition.each(function () {
16714 var schedule = set(this, id);
16715 (schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
16717 return function (node) {
16718 return get$1(node, id).value[name];
16722 function interpolate (a, b) {
16724 return (typeof b === "number" ? d3_interpolateNumber : b instanceof color ? d3_interpolateRgb : (c = color(b)) ? (b = c, d3_interpolateRgb) : interpolateString)(a, b);
16727 function attrRemove(name) {
16728 return function () {
16729 this.removeAttribute(name);
16733 function attrRemoveNS(fullname) {
16734 return function () {
16735 this.removeAttributeNS(fullname.space, fullname.local);
16739 function attrConstant(name, interpolate, value1) {
16741 string1 = value1 + "",
16743 return function () {
16744 var string0 = this.getAttribute(name);
16745 return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16749 function attrConstantNS(fullname, interpolate, value1) {
16751 string1 = value1 + "",
16753 return function () {
16754 var string0 = this.getAttributeNS(fullname.space, fullname.local);
16755 return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
16759 function attrFunction(name, interpolate, value) {
16760 var string00, string10, interpolate0;
16761 return function () {
16763 value1 = value(this),
16765 if (value1 == null) return void this.removeAttribute(name);
16766 string0 = this.getAttribute(name);
16767 string1 = value1 + "";
16768 return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16772 function attrFunctionNS(fullname, interpolate, value) {
16773 var string00, string10, interpolate0;
16774 return function () {
16776 value1 = value(this),
16778 if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
16779 string0 = this.getAttributeNS(fullname.space, fullname.local);
16780 string1 = value1 + "";
16781 return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
16785 function transition_attr (name, value) {
16786 var fullname = namespace(name),
16787 i = fullname === "transform" ? interpolateTransformSvg : interpolate;
16788 return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));
16791 function attrInterpolate(name, i) {
16792 return function (t) {
16793 this.setAttribute(name, i.call(this, t));
16797 function attrInterpolateNS(fullname, i) {
16798 return function (t) {
16799 this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
16803 function attrTweenNS(fullname, value) {
16807 var i = value.apply(this, arguments);
16808 if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
16812 tween._value = value;
16816 function attrTween(name, value) {
16820 var i = value.apply(this, arguments);
16821 if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
16825 tween._value = value;
16829 function transition_attrTween (name, value) {
16830 var key = "attr." + name;
16831 if (arguments.length < 2) return (key = this.tween(key)) && key._value;
16832 if (value == null) return this.tween(key, null);
16833 if (typeof value !== "function") throw new Error();
16834 var fullname = namespace(name);
16835 return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
16838 function delayFunction(id, value) {
16839 return function () {
16840 init(this, id).delay = +value.apply(this, arguments);
16844 function delayConstant(id, value) {
16845 return value = +value, function () {
16846 init(this, id).delay = value;
16850 function transition_delay (value) {
16852 return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get$1(this.node(), id).delay;
16855 function durationFunction(id, value) {
16856 return function () {
16857 set(this, id).duration = +value.apply(this, arguments);
16861 function durationConstant(id, value) {
16862 return value = +value, function () {
16863 set(this, id).duration = value;
16867 function transition_duration (value) {
16869 return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get$1(this.node(), id).duration;
16872 function easeConstant(id, value) {
16873 if (typeof value !== "function") throw new Error();
16874 return function () {
16875 set(this, id).ease = value;
16879 function transition_ease (value) {
16881 return arguments.length ? this.each(easeConstant(id, value)) : get$1(this.node(), id).ease;
16884 function easeVarying(id, value) {
16885 return function () {
16886 var v = value.apply(this, arguments);
16887 if (typeof v !== "function") throw new Error();
16888 set(this, id).ease = v;
16892 function transition_easeVarying (value) {
16893 if (typeof value !== "function") throw new Error();
16894 return this.each(easeVarying(this._id, value));
16897 function transition_filter (match) {
16898 if (typeof match !== "function") match = matcher(match);
16900 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16901 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
16902 if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
16903 subgroup.push(node);
16908 return new Transition(subgroups, this._parents, this._name, this._id);
16911 function transition_merge (transition) {
16912 if (transition._id !== this._id) throw new Error();
16914 for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
16915 for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
16916 if (node = group0[i] || group1[i]) {
16922 for (; j < m0; ++j) {
16923 merges[j] = groups0[j];
16926 return new Transition(merges, this._parents, this._name, this._id);
16929 function start(name) {
16930 return (name + "").trim().split(/^|\s+/).every(function (t) {
16931 var i = t.indexOf(".");
16932 if (i >= 0) t = t.slice(0, i);
16933 return !t || t === "start";
16937 function onFunction(id, name, listener) {
16940 sit = start(name) ? init : set;
16941 return function () {
16942 var schedule = sit(this, id),
16943 on = schedule.on; // If this node shared a dispatch with the previous node,
16944 // just assign the updated shared dispatch and we’re done!
16945 // Otherwise, copy-on-write.
16947 if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
16952 function transition_on (name, listener) {
16954 return arguments.length < 2 ? get$1(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
16957 function removeFunction(id) {
16958 return function () {
16959 var parent = this.parentNode;
16961 for (var i in this.__transition) {
16962 if (+i !== id) return;
16965 if (parent) parent.removeChild(this);
16969 function transition_remove () {
16970 return this.on("end.remove", removeFunction(this._id));
16973 function transition_select (select) {
16974 var name = this._name,
16976 if (typeof select !== "function") select = selector(select);
16978 for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
16979 for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
16980 if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
16981 if ("__data__" in node) subnode.__data__ = node.__data__;
16982 subgroup[i] = subnode;
16983 schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
16988 return new Transition(subgroups, this._parents, name, id);
16991 function transition_selectAll (select) {
16992 var name = this._name,
16994 if (typeof select !== "function") select = selectorAll(select);
16996 for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
16997 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
16998 if (node = group[i]) {
16999 for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
17000 if (child = children[k]) {
17001 schedule(child, name, id, k, children, inherit);
17005 subgroups.push(children);
17006 parents.push(node);
17011 return new Transition(subgroups, parents, name, id);
17014 var Selection = selection.prototype.constructor;
17015 function transition_selection () {
17016 return new Selection(this._groups, this._parents);
17019 function styleNull(name, interpolate) {
17020 var string00, string10, interpolate0;
17021 return function () {
17022 var string0 = styleValue(this, name),
17023 string1 = (this.style.removeProperty(name), styleValue(this, name));
17024 return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
17028 function styleRemove(name) {
17029 return function () {
17030 this.style.removeProperty(name);
17034 function styleConstant(name, interpolate, value1) {
17036 string1 = value1 + "",
17038 return function () {
17039 var string0 = styleValue(this, name);
17040 return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
17044 function styleFunction(name, interpolate, value) {
17045 var string00, string10, interpolate0;
17046 return function () {
17047 var string0 = styleValue(this, name),
17048 value1 = value(this),
17049 string1 = value1 + "";
17050 if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
17051 return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
17055 function styleMaybeRemove(id, name) {
17059 key = "style." + name,
17060 event = "end." + key,
17062 return function () {
17063 var schedule = set(this, id),
17065 listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : undefined; // If this node shared a dispatch with the previous node,
17066 // just assign the updated shared dispatch and we’re done!
17067 // Otherwise, copy-on-write.
17069 if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
17074 function transition_style (name, value, priority) {
17075 var i = (name += "") === "transform" ? interpolateTransformCss : interpolate;
17076 return value == null ? this.styleTween(name, styleNull(name, i)).on("end.style." + name, styleRemove(name)) : typeof value === "function" ? this.styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant(name, i, value), priority).on("end.style." + name, null);
17079 function styleInterpolate(name, i, priority) {
17080 return function (t) {
17081 this.style.setProperty(name, i.call(this, t), priority);
17085 function styleTween(name, value, priority) {
17089 var i = value.apply(this, arguments);
17090 if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
17094 tween._value = value;
17098 function transition_styleTween (name, value, priority) {
17099 var key = "style." + (name += "");
17100 if (arguments.length < 2) return (key = this.tween(key)) && key._value;
17101 if (value == null) return this.tween(key, null);
17102 if (typeof value !== "function") throw new Error();
17103 return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
17106 function textConstant(value) {
17107 return function () {
17108 this.textContent = value;
17112 function textFunction(value) {
17113 return function () {
17114 var value1 = value(this);
17115 this.textContent = value1 == null ? "" : value1;
17119 function transition_text (value) {
17120 return this.tween("text", typeof value === "function" ? textFunction(tweenValue(this, "text", value)) : textConstant(value == null ? "" : value + ""));
17123 function textInterpolate(i) {
17124 return function (t) {
17125 this.textContent = i.call(this, t);
17129 function textTween(value) {
17133 var i = value.apply(this, arguments);
17134 if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
17138 tween._value = value;
17142 function transition_textTween (value) {
17144 if (arguments.length < 1) return (key = this.tween(key)) && key._value;
17145 if (value == null) return this.tween(key, null);
17146 if (typeof value !== "function") throw new Error();
17147 return this.tween(key, textTween(value));
17150 function transition_transition () {
17151 var name = this._name,
17155 for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
17156 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
17157 if (node = group[i]) {
17158 var inherit = get$1(node, id0);
17159 schedule(node, name, id1, i, group, {
17160 time: inherit.time + inherit.delay + inherit.duration,
17162 duration: inherit.duration,
17169 return new Transition(groups, this._parents, name, id1);
17172 function transition_end () {
17177 size = that.size();
17178 return new Promise(function (resolve, reject) {
17183 value: function value() {
17184 if (--size === 0) resolve();
17187 that.each(function () {
17188 var schedule = set(this, id),
17189 on = schedule.on; // If this node shared a dispatch with the previous node,
17190 // just assign the updated shared dispatch and we’re done!
17191 // Otherwise, copy-on-write.
17194 on1 = (on0 = on).copy();
17196 on1._.cancel.push(cancel);
17198 on1._.interrupt.push(cancel);
17200 on1._.end.push(end);
17204 }); // The selection was empty, resolve end immediately
17206 if (size === 0) resolve();
17211 function Transition(groups, parents, name, id) {
17212 this._groups = groups;
17213 this._parents = parents;
17220 var selection_prototype = selection.prototype;
17221 Transition.prototype = _defineProperty({
17222 constructor: Transition,
17223 select: transition_select,
17224 selectAll: transition_selectAll,
17225 filter: transition_filter,
17226 merge: transition_merge,
17227 selection: transition_selection,
17228 transition: transition_transition,
17229 call: selection_prototype.call,
17230 nodes: selection_prototype.nodes,
17231 node: selection_prototype.node,
17232 size: selection_prototype.size,
17233 empty: selection_prototype.empty,
17234 each: selection_prototype.each,
17236 attr: transition_attr,
17237 attrTween: transition_attrTween,
17238 style: transition_style,
17239 styleTween: transition_styleTween,
17240 text: transition_text,
17241 textTween: transition_textTween,
17242 remove: transition_remove,
17243 tween: transition_tween,
17244 delay: transition_delay,
17245 duration: transition_duration,
17246 ease: transition_ease,
17247 easeVarying: transition_easeVarying,
17248 end: transition_end
17249 }, Symbol.iterator, selection_prototype[Symbol.iterator]);
17251 var linear$1 = function linear(t) {
17255 function cubicInOut(t) {
17256 return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
17259 var defaultTiming = {
17267 function inherit(node, id) {
17270 while (!(timing = node.__transition) || !(timing = timing[id])) {
17271 if (!(node = node.parentNode)) {
17272 throw new Error("transition ".concat(id, " not found"));
17279 function selection_transition (name) {
17282 if (name instanceof Transition) {
17283 id = name._id, name = name._name;
17285 id = newId(), (timing = defaultTiming).time = now$1(), name = name == null ? null : name + "";
17288 for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
17289 for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
17290 if (node = group[i]) {
17291 schedule(node, name, id, i, group, timing || inherit(node, id));
17296 return new Transition(groups, this._parents, name, id);
17299 selection.prototype.interrupt = selection_interrupt;
17300 selection.prototype.transition = selection_transition;
17302 var constant = (function (x) {
17303 return function () {
17308 function ZoomEvent(type, _ref) {
17309 var sourceEvent = _ref.sourceEvent,
17310 target = _ref.target,
17311 transform = _ref.transform,
17312 dispatch = _ref.dispatch;
17313 Object.defineProperties(this, {
17320 value: sourceEvent,
17340 function Transform(k, x, y) {
17345 Transform.prototype = {
17346 constructor: Transform,
17347 scale: function scale(k) {
17348 return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
17350 translate: function translate(x, y) {
17351 return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
17353 apply: function apply(point) {
17354 return [point[0] * this.k + this.x, point[1] * this.k + this.y];
17356 applyX: function applyX(x) {
17357 return x * this.k + this.x;
17359 applyY: function applyY(y) {
17360 return y * this.k + this.y;
17362 invert: function invert(location) {
17363 return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
17365 invertX: function invertX(x) {
17366 return (x - this.x) / this.k;
17368 invertY: function invertY(y) {
17369 return (y - this.y) / this.k;
17371 rescaleX: function rescaleX(x) {
17372 return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
17374 rescaleY: function rescaleY(y) {
17375 return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
17377 toString: function toString() {
17378 return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
17381 var identity$2 = new Transform(1, 0, 0);
17383 function nopropagation(event) {
17384 event.stopImmediatePropagation();
17386 function noevent (event) {
17387 event.preventDefault();
17388 event.stopImmediatePropagation();
17391 // except for pinch-to-zoom, which is sent as a wheel+ctrlKey event
17393 function defaultFilter$1(event) {
17394 return (!event.ctrlKey || event.type === 'wheel') && !event.button;
17397 function defaultExtent$1() {
17400 if (e instanceof SVGElement) {
17401 e = e.ownerSVGElement || e;
17403 if (e.hasAttribute("viewBox")) {
17404 e = e.viewBox.baseVal;
17405 return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
17408 return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
17411 return [[0, 0], [e.clientWidth, e.clientHeight]];
17414 function defaultTransform() {
17415 return this.__zoom || identity$2;
17418 function defaultWheelDelta$1(event) {
17419 return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 0.002) * (event.ctrlKey ? 10 : 1);
17422 function defaultTouchable() {
17423 return navigator.maxTouchPoints || "ontouchstart" in this;
17426 function defaultConstrain$1(transform, extent, translateExtent) {
17427 var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
17428 dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
17429 dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
17430 dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
17431 return transform.translate(dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1), dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1));
17434 function d3_zoom () {
17435 var filter = defaultFilter$1,
17436 extent = defaultExtent$1,
17437 constrain = defaultConstrain$1,
17438 wheelDelta = defaultWheelDelta$1,
17439 touchable = defaultTouchable,
17440 scaleExtent = [0, Infinity],
17441 translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
17443 interpolate = interpolateZoom,
17444 listeners = dispatch$8("start", "zoom", "end"),
17450 clickDistance2 = 0,
17453 function zoom(selection) {
17454 selection.property("__zoom", defaultTransform).on("wheel.zoom", wheeled).on("mousedown.zoom", mousedowned).on("dblclick.zoom", dblclicked).filter(touchable).on("touchstart.zoom", touchstarted).on("touchmove.zoom", touchmoved).on("touchend.zoom touchcancel.zoom", touchended).style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
17457 zoom.transform = function (collection, transform, point, event) {
17458 var selection = collection.selection ? collection.selection() : collection;
17459 selection.property("__zoom", defaultTransform);
17461 if (collection !== selection) {
17462 schedule(collection, transform, point, event);
17464 selection.interrupt().each(function () {
17465 gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
17470 zoom.scaleBy = function (selection, k, p, event) {
17471 zoom.scaleTo(selection, function () {
17472 var k0 = this.__zoom.k,
17473 k1 = typeof k === "function" ? k.apply(this, arguments) : k;
17478 zoom.scaleTo = function (selection, k, p, event) {
17479 zoom.transform(selection, function () {
17480 var e = extent.apply(this, arguments),
17482 p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p,
17483 p1 = t0.invert(p0),
17484 k1 = typeof k === "function" ? k.apply(this, arguments) : k;
17485 return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
17489 zoom.translateBy = function (selection, x, y, event) {
17490 zoom.transform(selection, function () {
17491 return constrain(this.__zoom.translate(typeof x === "function" ? x.apply(this, arguments) : x, typeof y === "function" ? y.apply(this, arguments) : y), extent.apply(this, arguments), translateExtent);
17495 zoom.translateTo = function (selection, x, y, p, event) {
17496 zoom.transform(selection, function () {
17497 var e = extent.apply(this, arguments),
17499 p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
17500 return constrain(identity$2.translate(p0[0], p0[1]).scale(t.k).translate(typeof x === "function" ? -x.apply(this, arguments) : -x, typeof y === "function" ? -y.apply(this, arguments) : -y), e, translateExtent);
17504 function scale(transform, k) {
17505 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
17506 return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
17509 function translate(transform, p0, p1) {
17510 var x = p0[0] - p1[0] * transform.k,
17511 y = p0[1] - p1[1] * transform.k;
17512 return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
17515 function centroid(extent) {
17516 return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
17519 function schedule(transition, transform, point, event) {
17520 transition.on("start.zoom", function () {
17521 gesture(this, arguments).event(event).start();
17522 }).on("interrupt.zoom end.zoom", function () {
17523 gesture(this, arguments).event(event).end();
17524 }).tween("zoom", function () {
17527 g = gesture(that, args).event(event),
17528 e = extent.apply(that, args),
17529 p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point,
17530 w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
17532 b = typeof transform === "function" ? transform.apply(that, args) : transform,
17533 i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
17534 return function (t) {
17535 if (t === 1) t = b; // Avoid rounding error on end.
17539 t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
17546 function gesture(that, args, clean) {
17547 return !clean && that.__zooming || new Gesture(that, args);
17550 function Gesture(that, args) {
17554 this.sourceEvent = null;
17555 this.extent = extent.apply(that, args);
17559 Gesture.prototype = {
17560 event: function event(_event) {
17561 if (_event) this.sourceEvent = _event;
17564 start: function start() {
17565 if (++this.active === 1) {
17566 this.that.__zooming = this;
17567 this.emit("start");
17572 zoom: function zoom(key, transform) {
17573 if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
17574 if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
17575 if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
17576 this.that.__zoom = transform;
17580 end: function end() {
17581 if (--this.active === 0) {
17582 delete this.that.__zooming;
17588 emit: function emit(type) {
17589 var d = select(this.that).datum();
17590 listeners.call(type, this.that, new ZoomEvent(type, {
17591 sourceEvent: this.sourceEvent,
17594 transform: this.that.__zoom,
17595 dispatch: listeners
17600 function wheeled(event) {
17601 for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
17602 args[_key - 1] = arguments[_key];
17605 if (!filter.apply(this, arguments)) return;
17606 var g = gesture(this, args).event(event),
17608 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
17609 p = pointer(event); // If the mouse is in the same location as before, reuse it.
17610 // If there were recent wheel events, reset the wheel idle timeout.
17613 if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
17614 g.mouse[1] = t.invert(g.mouse[0] = p);
17617 clearTimeout(g.wheel);
17618 } // If this wheel event won’t trigger a transform change, ignore it.
17619 else if (t.k === k) return; // Otherwise, capture the mouse point and location at the start.
17621 g.mouse = [p, t.invert(p)];
17627 g.wheel = setTimeout(wheelidled, wheelDelay);
17628 g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
17630 function wheelidled() {
17636 function mousedowned(event) {
17637 for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
17638 args[_key2 - 1] = arguments[_key2];
17641 if (touchending || !filter.apply(this, arguments)) return;
17642 var g = gesture(this, args, true).event(event),
17643 v = select(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
17644 p = pointer(event, currentTarget),
17645 currentTarget = event.currentTarget,
17646 x0 = event.clientX,
17647 y0 = event.clientY;
17648 dragDisable(event.view);
17649 nopropagation(event);
17650 g.mouse = [p, this.__zoom.invert(p)];
17654 function mousemoved(event) {
17658 var dx = event.clientX - x0,
17659 dy = event.clientY - y0;
17660 g.moved = dx * dx + dy * dy > clickDistance2;
17663 g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
17666 function mouseupped(event) {
17667 v.on("mousemove.zoom mouseup.zoom", null);
17668 yesdrag(event.view, g.moved);
17670 g.event(event).end();
17674 function dblclicked(event) {
17675 for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
17676 args[_key3 - 1] = arguments[_key3];
17679 if (!filter.apply(this, arguments)) return;
17680 var t0 = this.__zoom,
17681 p0 = pointer(event.changedTouches ? event.changedTouches[0] : event, this),
17682 p1 = t0.invert(p0),
17683 k1 = t0.k * (event.shiftKey ? 0.5 : 2),
17684 t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
17686 if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0, event);else select(this).call(zoom.transform, t1, p0, event);
17689 function touchstarted(event) {
17690 for (var _len4 = arguments.length, args = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
17691 args[_key4 - 1] = arguments[_key4];
17694 if (!filter.apply(this, arguments)) return;
17695 var touches = event.touches,
17696 n = touches.length,
17697 g = gesture(this, args, event.changedTouches.length === n).event(event),
17702 nopropagation(event);
17704 for (i = 0; i < n; ++i) {
17705 t = touches[i], p = pointer(t, this);
17706 p = [p, this.__zoom.invert(p), t.identifier];
17707 if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting;else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0;
17710 if (touchstarting) touchstarting = clearTimeout(touchstarting);
17713 if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function () {
17714 touchstarting = null;
17721 function touchmoved(event) {
17722 if (!this.__zooming) return;
17724 for (var _len5 = arguments.length, args = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
17725 args[_key5 - 1] = arguments[_key5];
17728 var g = gesture(this, args).event(event),
17729 touches = event.changedTouches,
17730 n = touches.length,
17737 for (i = 0; i < n; ++i) {
17738 t = touches[i], p = pointer(t, this);
17739 if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
17745 var p0 = g.touch0[0],
17749 dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
17750 dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
17751 t = scale(t, Math.sqrt(dp / dl));
17752 p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
17753 l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
17754 } else if (g.touch0) p = g.touch0[0], l = g.touch0[1];else return;
17756 g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
17759 function touchended(event) {
17760 for (var _len6 = arguments.length, args = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) {
17761 args[_key6 - 1] = arguments[_key6];
17764 if (!this.__zooming) return;
17765 var g = gesture(this, args).event(event),
17766 touches = event.changedTouches,
17767 n = touches.length,
17770 nopropagation(event);
17771 if (touchending) clearTimeout(touchending);
17772 touchending = setTimeout(function () {
17773 touchending = null;
17776 for (i = 0; i < n; ++i) {
17778 if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
17781 if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
17782 if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);else {
17783 g.end(); // If this was a dbltap, reroute to the (optional) dblclick.zoom handler.
17785 if (g.taps === 2) {
17786 t = pointer(t, this);
17788 if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
17789 var p = select(this).on("dblclick.zoom");
17790 if (p) p.apply(this, arguments);
17796 zoom.wheelDelta = function (_) {
17797 return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant(+_), zoom) : wheelDelta;
17800 zoom.filter = function (_) {
17801 return arguments.length ? (filter = typeof _ === "function" ? _ : constant(!!_), zoom) : filter;
17804 zoom.touchable = function (_) {
17805 return arguments.length ? (touchable = typeof _ === "function" ? _ : constant(!!_), zoom) : touchable;
17808 zoom.extent = function (_) {
17809 return arguments.length ? (extent = typeof _ === "function" ? _ : constant([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
17812 zoom.scaleExtent = function (_) {
17813 return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
17816 zoom.translateExtent = function (_) {
17817 return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
17820 zoom.constrain = function (_) {
17821 return arguments.length ? (constrain = _, zoom) : constrain;
17824 zoom.duration = function (_) {
17825 return arguments.length ? (duration = +_, zoom) : duration;
17828 zoom.interpolate = function (_) {
17829 return arguments.length ? (interpolate = _, zoom) : interpolate;
17832 zoom.on = function () {
17833 var value = listeners.on.apply(listeners, arguments);
17834 return value === listeners ? zoom : value;
17837 zoom.clickDistance = function (_) {
17838 return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
17841 zoom.tapDistance = function (_) {
17842 return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
17849 Bypasses features of D3's default projection stream pipeline that are unnecessary:
17850 * Antimeridian clipping
17851 * Spherical rotation
17855 function geoRawMercator() {
17856 var project = mercatorRaw;
17857 var k = 512 / Math.PI; // scale
17860 var y = 0; // translate
17862 var clipExtent = [[0, 0], [0, 0]];
17864 function projection(point) {
17865 point = project(point[0] * Math.PI / 180, point[1] * Math.PI / 180);
17866 return [point[0] * k + x, y - point[1] * k];
17869 projection.invert = function (point) {
17870 point = project.invert((point[0] - x) / k, (y - point[1]) / k);
17871 return point && [point[0] * 180 / Math.PI, point[1] * 180 / Math.PI];
17874 projection.scale = function (_) {
17875 if (!arguments.length) return k;
17880 projection.translate = function (_) {
17881 if (!arguments.length) return [x, y];
17887 projection.clipExtent = function (_) {
17888 if (!arguments.length) return clipExtent;
17893 projection.transform = function (obj) {
17894 if (!arguments.length) return identity$2.translate(x, y).scale(k);
17901 projection.stream = d3_geoTransform({
17902 point: function point(x, y) {
17903 var vec = projection([x, y]);
17904 this.stream.point(vec[0], vec[1]);
17910 function geoOrthoNormalizedDotProduct(a, b, origin) {
17911 if (geoVecEqual(origin, a) || geoVecEqual(origin, b)) {
17912 return 1; // coincident points, treat as straight and try to remove
17915 return geoVecNormalizedDot(a, b, origin);
17918 function geoOrthoFilterDotProduct(dotp, epsilon, lowerThreshold, upperThreshold, allowStraightAngles) {
17919 var val = Math.abs(dotp);
17921 if (val < epsilon) {
17922 return 0; // already orthogonal
17923 } else if (allowStraightAngles && Math.abs(val - 1) < epsilon) {
17924 return 0; // straight angle, which is okay in this case
17925 } else if (val < lowerThreshold || val > upperThreshold) {
17926 return dotp; // can be adjusted
17928 return null; // ignore vertex
17932 function geoOrthoCalcScore(points, isClosed, epsilon, threshold) {
17934 var first = isClosed ? 0 : 1;
17935 var last = isClosed ? points.length : points.length - 1;
17936 var coords = points.map(function (p) {
17939 var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17940 var upperThreshold = Math.cos(threshold * Math.PI / 180);
17942 for (var i = first; i < last; i++) {
17943 var a = coords[(i - 1 + coords.length) % coords.length];
17944 var origin = coords[i];
17945 var b = coords[(i + 1) % coords.length];
17946 var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold);
17947 if (dotp === null) continue; // ignore vertex
17949 score = score + 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
17953 } // returns the maximum angle less than `lessThan` between the actual corner and a 0° or 90° corner
17955 function geoOrthoMaxOffsetAngle(coords, isClosed, lessThan) {
17956 var max = -Infinity;
17957 var first = isClosed ? 0 : 1;
17958 var last = isClosed ? coords.length : coords.length - 1;
17960 for (var i = first; i < last; i++) {
17961 var a = coords[(i - 1 + coords.length) % coords.length];
17962 var origin = coords[i];
17963 var b = coords[(i + 1) % coords.length];
17964 var normalizedDotP = geoOrthoNormalizedDotProduct(a, b, origin);
17965 var angle = Math.acos(Math.abs(normalizedDotP)) * 180 / Math.PI;
17966 if (angle > 45) angle = 90 - angle;
17967 if (angle >= lessThan) continue;
17968 if (angle > max) max = angle;
17971 if (max === -Infinity) return null;
17973 } // similar to geoOrthoCalcScore, but returns quickly if there is something to do
17975 function geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles) {
17977 var first = isClosed ? 0 : 1;
17978 var last = isClosed ? coords.length : coords.length - 1;
17979 var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
17980 var upperThreshold = Math.cos(threshold * Math.PI / 180);
17982 for (var i = first; i < last; i++) {
17983 var a = coords[(i - 1 + coords.length) % coords.length];
17984 var origin = coords[i];
17985 var b = coords[(i + 1) % coords.length];
17986 var dotp = geoOrthoFilterDotProduct(geoOrthoNormalizedDotProduct(a, b, origin), epsilon, lowerThreshold, upperThreshold, allowStraightAngles);
17987 if (dotp === null) continue; // ignore vertex
17989 if (Math.abs(dotp) > 0) return 1; // something to do
17991 score = 0; // already square
17998 var FREEZING = freezing;
17999 var fails$9 = fails$N;
18000 var isObject$4 = isObject$r;
18001 var onFreeze = internalMetadata.exports.onFreeze;
18003 // eslint-disable-next-line es/no-object-freeze -- safe
18004 var $freeze = Object.freeze;
18005 var FAILS_ON_PRIMITIVES = fails$9(function () { $freeze(1); });
18007 // `Object.freeze` method
18008 // https://tc39.es/ecma262/#sec-object.freeze
18009 $$l({ target: 'Object', stat: true, forced: FAILS_ON_PRIMITIVES, sham: !FREEZING }, {
18010 freeze: function freeze(it) {
18011 return $freeze && isObject$4(it) ? $freeze(onFreeze(it)) : it;
18015 // Returns true if a and b have the same elements at the same indices.
18016 function utilArrayIdentical(a, b) {
18017 // an array is always identical to itself
18018 if (a === b) return true;
18020 if (i !== b.length) return false;
18023 if (a[i] !== b[i]) return false;
18027 } // http://2ality.com/2015/01/es6-set-operations.html
18028 // Difference (a \ b): create a set that contains those elements of set a that are not in set b.
18029 // This operation is also sometimes called minus (-).
18030 // var a = [1,2,3];
18031 // var b = [4,3,2];
18032 // utilArrayDifference(a, b)
18034 // utilArrayDifference(b, a)
18037 function utilArrayDifference(a, b) {
18038 var other = new Set(b);
18039 return Array.from(new Set(a)).filter(function (v) {
18040 return !other.has(v);
18042 } // Intersection (a ∩ b): create a set that contains those elements of set a that are also in set b.
18043 // var a = [1,2,3];
18044 // var b = [4,3,2];
18045 // utilArrayIntersection(a, b)
18048 function utilArrayIntersection(a, b) {
18049 var other = new Set(b);
18050 return Array.from(new Set(a)).filter(function (v) {
18051 return other.has(v);
18053 } // Union (a ∪ b): create a set that contains the elements of both set a and set b.
18054 // var a = [1,2,3];
18055 // var b = [4,3,2];
18056 // utilArrayUnion(a, b)
18059 function utilArrayUnion(a, b) {
18060 var result = new Set(a);
18061 b.forEach(function (v) {
18064 return Array.from(result);
18065 } // Returns an Array with all the duplicates removed
18066 // var a = [1,1,2,3,3];
18067 // utilArrayUniq(a)
18070 function utilArrayUniq(a) {
18071 return Array.from(new Set(a));
18072 } // Splits array into chunks of given chunk size
18073 // var a = [1,2,3,4,5,6,7];
18074 // utilArrayChunk(a, 3);
18075 // [[1,2,3],[4,5,6],[7]];
18077 function utilArrayChunk(a, chunkSize) {
18078 if (!chunkSize || chunkSize < 0) return [a.slice()];
18079 var result = new Array(Math.ceil(a.length / chunkSize));
18080 return Array.from(result, function (item, i) {
18081 return a.slice(i * chunkSize, i * chunkSize + chunkSize);
18083 } // Flattens two level array into a single level
18084 // var a = [[1,2,3],[4,5,6],[7]];
18085 // utilArrayFlatten(a);
18086 // [1,2,3,4,5,6,7];
18088 function utilArrayFlatten(a) {
18089 return a.reduce(function (acc, val) {
18090 return acc.concat(val);
18092 } // Groups the items of the Array according to the given key
18093 // `key` can be passed as a property or as a key function
18096 // { type: 'Dog', name: 'Spot' },
18097 // { type: 'Cat', name: 'Tiger' },
18098 // { type: 'Dog', name: 'Rover' },
18099 // { type: 'Cat', name: 'Leo' }
18102 // utilArrayGroupBy(pets, 'type')
18104 // 'Dog': [{type: 'Dog', name: 'Spot'}, {type: 'Dog', name: 'Rover'}],
18105 // 'Cat': [{type: 'Cat', name: 'Tiger'}, {type: 'Cat', name: 'Leo'}]
18108 // utilArrayGroupBy(pets, function(item) { return item.name.length; })
18110 // 3: [{type: 'Cat', name: 'Leo'}],
18111 // 4: [{type: 'Dog', name: 'Spot'}],
18112 // 5: [{type: 'Cat', name: 'Tiger'}, {type: 'Dog', name: 'Rover'}]
18115 function utilArrayGroupBy(a, key) {
18116 return a.reduce(function (acc, item) {
18117 var group = typeof key === 'function' ? key(item) : item[key];
18118 (acc[group] = acc[group] || []).push(item);
18121 } // Returns an Array with all the duplicates removed
18122 // where uniqueness determined by the given key
18123 // `key` can be passed as a property or as a key function
18126 // { type: 'Dog', name: 'Spot' },
18127 // { type: 'Cat', name: 'Tiger' },
18128 // { type: 'Dog', name: 'Rover' },
18129 // { type: 'Cat', name: 'Leo' }
18132 // utilArrayUniqBy(pets, 'type')
18134 // { type: 'Dog', name: 'Spot' },
18135 // { type: 'Cat', name: 'Tiger' }
18138 // utilArrayUniqBy(pets, function(item) { return item.name.length; })
18140 // { type: 'Dog', name: 'Spot' },
18141 // { type: 'Cat', name: 'Tiger' },
18142 // { type: 'Cat', name: 'Leo' }
18145 function utilArrayUniqBy(a, key) {
18146 var seen = new Set();
18147 return a.reduce(function (acc, item) {
18148 var val = typeof key === 'function' ? key(item) : item[key];
18150 if (val && !seen.has(val)) {
18159 var DESCRIPTORS$2 = descriptors;
18160 var global$2 = global$F;
18161 var isForced = isForced_1;
18162 var redefine$1 = redefine$g.exports;
18164 var classof$1 = classofRaw$1;
18165 var inheritIfRequired = inheritIfRequired$4;
18166 var toPrimitive$1 = toPrimitive$7;
18167 var fails$8 = fails$N;
18168 var create$2 = objectCreate;
18169 var getOwnPropertyNames = objectGetOwnPropertyNames.f;
18170 var getOwnPropertyDescriptor$2 = objectGetOwnPropertyDescriptor.f;
18171 var defineProperty = objectDefineProperty.f;
18172 var trim$2 = stringTrim.trim;
18174 var NUMBER = 'Number';
18175 var NativeNumber = global$2[NUMBER];
18176 var NumberPrototype = NativeNumber.prototype;
18178 // Opera ~12 has broken Object#toString
18179 var BROKEN_CLASSOF = classof$1(create$2(NumberPrototype)) == NUMBER;
18181 // `ToNumber` abstract operation
18182 // https://tc39.es/ecma262/#sec-tonumber
18183 var toNumber$1 = function (argument) {
18184 var it = toPrimitive$1(argument, false);
18185 var first, third, radix, maxCode, digits, length, index, code;
18186 if (typeof it == 'string' && it.length > 2) {
18188 first = it.charCodeAt(0);
18189 if (first === 43 || first === 45) {
18190 third = it.charCodeAt(2);
18191 if (third === 88 || third === 120) return NaN; // Number('+0x1') should be NaN, old V8 fix
18192 } else if (first === 48) {
18193 switch (it.charCodeAt(1)) {
18194 case 66: case 98: radix = 2; maxCode = 49; break; // fast equal of /^0b[01]+$/i
18195 case 79: case 111: radix = 8; maxCode = 55; break; // fast equal of /^0o[0-7]+$/i
18196 default: return +it;
18198 digits = it.slice(2);
18199 length = digits.length;
18200 for (index = 0; index < length; index++) {
18201 code = digits.charCodeAt(index);
18202 // parseInt parses a string to a first unavailable symbol
18203 // but ToNumber should return NaN if a string contains unavailable symbols
18204 if (code < 48 || code > maxCode) return NaN;
18205 } return parseInt(digits, radix);
18210 // `Number` constructor
18211 // https://tc39.es/ecma262/#sec-number-constructor
18212 if (isForced(NUMBER, !NativeNumber(' 0o1') || !NativeNumber('0b1') || NativeNumber('+0x1'))) {
18213 var NumberWrapper = function Number(value) {
18214 var it = arguments.length < 1 ? 0 : value;
18216 return dummy instanceof NumberWrapper
18217 // check on 1..constructor(foo) case
18218 && (BROKEN_CLASSOF ? fails$8(function () { NumberPrototype.valueOf.call(dummy); }) : classof$1(dummy) != NUMBER)
18219 ? inheritIfRequired(new NativeNumber(toNumber$1(it)), dummy, NumberWrapper) : toNumber$1(it);
18221 for (var keys = DESCRIPTORS$2 ? getOwnPropertyNames(NativeNumber) : (
18223 'MAX_VALUE,MIN_VALUE,NaN,NEGATIVE_INFINITY,POSITIVE_INFINITY,' +
18224 // ES2015 (in case, if modules with ES2015 Number statics required before):
18225 'EPSILON,isFinite,isInteger,isNaN,isSafeInteger,MAX_SAFE_INTEGER,' +
18226 'MIN_SAFE_INTEGER,parseFloat,parseInt,isInteger,' +
18229 ).split(','), j$1 = 0, key; keys.length > j$1; j$1++) {
18230 if (has(NativeNumber, key = keys[j$1]) && !has(NumberWrapper, key)) {
18231 defineProperty(NumberWrapper, key, getOwnPropertyDescriptor$2(NativeNumber, key));
18234 NumberWrapper.prototype = NumberPrototype;
18235 NumberPrototype.constructor = NumberWrapper;
18236 redefine$1(global$2, NUMBER, NumberWrapper);
18239 var fixRegExpWellKnownSymbolLogic$1 = fixRegexpWellKnownSymbolLogic;
18240 var anObject$1 = anObject$m;
18241 var toLength$3 = toLength$q;
18242 var requireObjectCoercible$7 = requireObjectCoercible$e;
18243 var advanceStringIndex = advanceStringIndex$3;
18244 var regExpExec$1 = regexpExecAbstract;
18247 fixRegExpWellKnownSymbolLogic$1('match', function (MATCH, nativeMatch, maybeCallNative) {
18249 // `String.prototype.match` method
18250 // https://tc39.es/ecma262/#sec-string.prototype.match
18251 function match(regexp) {
18252 var O = requireObjectCoercible$7(this);
18253 var matcher = regexp == undefined ? undefined : regexp[MATCH];
18254 return matcher !== undefined ? matcher.call(regexp, O) : new RegExp(regexp)[MATCH](String(O));
18256 // `RegExp.prototype[@@match]` method
18257 // https://tc39.es/ecma262/#sec-regexp.prototype-@@match
18258 function (string) {
18259 var res = maybeCallNative(nativeMatch, this, string);
18260 if (res.done) return res.value;
18262 var rx = anObject$1(this);
18263 var S = String(string);
18265 if (!rx.global) return regExpExec$1(rx, S);
18267 var fullUnicode = rx.unicode;
18272 while ((result = regExpExec$1(rx, S)) !== null) {
18273 var matchStr = String(result[0]);
18275 if (matchStr === '') rx.lastIndex = advanceStringIndex(S, toLength$3(rx.lastIndex), fullUnicode);
18278 return n === 0 ? null : A;
18283 var diacritics = {};
18285 var remove$6 = diacritics.remove = removeDiacritics;
18286 var replacementList = [{
18294 chars: "\u24B6\uFF21\xC0\xC1\xC2\u1EA6\u1EA4\u1EAA\u1EA8\xC3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\xC4\u01DE\u1EA2\xC5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F"
18300 chars: "\xC6\u01FC\u01E2"
18309 chars: "\uA738\uA73A"
18315 chars: "\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0181"
18318 chars: "\u24B8\uFF23\uA73E\u1E08\u0106C\u0108\u010A\u010C\xC7\u0187\u023B"
18321 chars: "\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018A\u0189\u1D05\uA779"
18327 chars: "\u01F1\u01C4"
18330 chars: "\u01F2\u01C5"
18333 chars: "\u025B\u24BA\uFF25\xC8\xC9\xCA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\xCB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E\u1D07"
18336 chars: "\uA77C\u24BB\uFF26\u1E1E\u0191\uA77B"
18339 chars: "\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E\u0262"
18342 chars: "\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D"
18345 chars: "\u24BE\uFF29\xCC\xCD\xCE\u0128\u012A\u012C\u0130\xCF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197"
18348 chars: "\u24BF\uFF2A\u0134\u0248\u0237"
18351 chars: "\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2"
18354 chars: "\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780"
18363 chars: "\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C\u03FB"
18366 chars: "\uA7A4\u0220\u24C3\uFF2E\u01F8\u0143\xD1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u019D\uA790\u1D0E"
18375 chars: "\u24C4\uFF2F\xD2\xD3\xD4\u1ED2\u1ED0\u1ED6\u1ED4\xD5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\xD6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\xD8\u01FE\u0186\u019F\uA74A\uA74C"
18390 chars: "\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754"
18393 chars: "\u24C6\uFF31\uA756\uA758\u024A"
18396 chars: "\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782"
18399 chars: "\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784"
18402 chars: "\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786"
18411 chars: "\u24CA\uFF35\xD9\xDA\xDB\u0168\u1E78\u016A\u1E7A\u016C\xDC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244"
18414 chars: "\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245"
18420 chars: "\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72"
18423 chars: "\u24CD\uFF38\u1E8A\u1E8C"
18426 chars: "\u24CE\uFF39\u1EF2\xDD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE"
18429 chars: "\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762"
18432 chars: "\u24D0\uFF41\u1E9A\xE0\xE1\xE2\u1EA7\u1EA5\u1EAB\u1EA9\xE3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\xE4\u01DF\u1EA3\xE5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250\u0251"
18438 chars: "\xE6\u01FD\u01E3"
18447 chars: "\uA739\uA73B"
18453 chars: "\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0182"
18456 chars: "\uFF43\u24D2\u0107\u0109\u010B\u010D\xE7\u1E09\u0188\u023C\uA73F\u2184"
18459 chars: "\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\u018B\u13E7\u0501\uA7AA"
18465 chars: "\u01F3\u01C6"
18468 chars: "\u24D4\uFF45\xE8\xE9\xEA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\xEB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u01DD"
18471 chars: "\u24D5\uFF46\u1E1F\u0192"
18489 chars: "\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\uA77F\u1D79"
18492 chars: "\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265"
18498 chars: "\u24D8\uFF49\xEC\xED\xEE\u0129\u012B\u012D\xEF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131"
18501 chars: "\u24D9\uFF4A\u0135\u01F0\u0249"
18504 chars: "\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3"
18507 chars: "\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u026D"
18513 chars: "\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F"
18516 chars: "\u24DD\uFF4E\u01F9\u0144\xF1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u043B\u0509"
18522 chars: "\u24DE\uFF4F\xF2\xF3\xF4\u1ED3\u1ED1\u1ED7\u1ED5\xF5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\xF6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\xF8\u01FF\uA74B\uA74D\u0275\u0254\u1D11"
18537 chars: "\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u03C1"
18540 chars: "\u24E0\uFF51\u024B\uA757\uA759"
18543 chars: "\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783"
18546 chars: "\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0282"
18552 chars: "\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787"
18561 chars: "\u24E4\uFF55\xF9\xFA\xFB\u0169\u1E79\u016B\u1E7B\u016D\xFC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289"
18564 chars: "\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C"
18570 chars: "\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73"
18573 chars: "\u24E7\uFF58\u1E8B\u1E8D"
18576 chars: "\u24E8\uFF59\u1EF3\xFD\u0177\u1EF9\u0233\u1E8F\xFF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF"
18579 chars: "\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763"
18581 var diacriticsMap = {};
18583 for (var i$1 = 0; i$1 < replacementList.length; i$1 += 1) {
18584 var chars = replacementList[i$1].chars;
18586 for (var j = 0; j < chars.length; j += 1) {
18587 diacriticsMap[chars[j]] = replacementList[i$1].base;
18591 function removeDiacritics(str) {
18592 return str.replace(/[^\u0000-\u007e]/g, function (c) {
18593 return diacriticsMap[c] || c;
18597 diacritics.replacementList = replacementList;
18598 diacritics.diacriticsMap = diacriticsMap;
18602 var isArabic$1 = {};
18604 Object.defineProperty(isArabic$1, "__esModule", {
18607 var arabicBlocks = [[0x0600, 0x06FF], [0x0750, 0x077F], [0x08A0, 0x08FF], [0xFB50, 0xFDFF], [0xFE70, 0xFEFF], [0x10E60, 0x10E7F], [0x1EC70, 0x1ECBF], [0x1EE00, 0x1EEFF] // Mathematical Alphabetic symbols https://www.unicode.org/charts/PDF/U1EE00.pdf
18610 function isArabic(_char) {
18611 if (_char.length > 1) {
18612 // allow the newer chars?
18613 throw new Error('isArabic works on only one-character strings');
18616 var code = _char.charCodeAt(0);
18618 for (var i = 0; i < arabicBlocks.length; i++) {
18619 var block = arabicBlocks[i];
18621 if (code >= block[0] && code <= block[1]) {
18629 isArabic$1.isArabic = isArabic;
18631 function isMath(_char2) {
18632 if (_char2.length > 2) {
18633 // allow the newer chars?
18634 throw new Error('isMath works on only one-character strings');
18637 var code = _char2.charCodeAt(0);
18639 return code >= 0x660 && code <= 0x66C || code >= 0x6F0 && code <= 0x6F9;
18642 isArabic$1.isMath = isMath;
18644 var GlyphSplitter$1 = {};
18646 var reference = {};
18648 var unicodeArabic = {};
18650 Object.defineProperty(unicodeArabic, "__esModule", {
18653 var arabicReference = {
18655 "normal": ["\u0627"],
18657 "normal": ["\u0627\u0653", "\u0622"],
18658 "isolated": "\uFE81",
18662 "normal": ["\u0627\u0654", "\u0623"],
18663 "isolated": "\uFE83",
18667 "normal": ["\u0627\u0655", "\u0625"],
18668 "isolated": "\uFE87",
18672 "normal": "\u0671",
18673 "isolated": "\uFB50",
18676 "wavy_hamza_above": ["\u0672"],
18677 "wavy_hamza_below": ["\u0627\u065F", "\u0673"],
18678 "high_hamza": ["\u0675", "\u0627\u0674"],
18679 "indic_two_above": ["\u0773"],
18680 "indic_three_above": ["\u0774"],
18682 "normal": ["\u0627\u064B"],
18684 "isolated": "\uFD3D"
18686 "isolated": "\uFE8D",
18690 "normal": ["\u0628"],
18691 "dotless": ["\u066E"],
18692 "three_dots_horizontally_below": ["\u0750"],
18693 "dot_below_three_dots_above": ["\u0751"],
18694 "three_dots_pointing_upwards_below": ["\u0752"],
18695 "three_dots_pointing_upwards_below_two_dots_above": ["\u0753"],
18696 "two_dots_below_dot_above": ["\u0754"],
18697 "inverted_small_v_below": ["\u0755"],
18698 "small_v": ["\u0756"],
18699 "small_v_below": ["\u08A0"],
18700 "hamza_above": ["\u08A1"],
18701 "small_meem_above": ["\u08B6"],
18702 "isolated": "\uFE8F",
18704 "initial": "\uFE91",
18708 "normal": ["\u0629"],
18709 "isolated": "\uFE93",
18713 "normal": ["\u062A"],
18714 "ring": ["\u067C"],
18715 "three_dots_above_downwards": ["\u067D"],
18716 "small_teh_above": ["\u08B8"],
18717 "isolated": "\uFE95",
18719 "initial": "\uFE97",
18723 "normal": ["\u062B"],
18724 "isolated": "\uFE99",
18726 "initial": "\uFE9B",
18730 "normal": ["\u062C"],
18731 "two_dots_above": ["\u08A2"],
18732 "isolated": "\uFE9D",
18734 "initial": "\uFE9F",
18738 "normal": ["\u062D"],
18739 "hamza_above": ["\u0681"],
18740 "two_dots_vertical_above": ["\u0682"],
18741 "three_dots_above": ["\u0685"],
18742 "two_dots_above": ["\u0757"],
18743 "three_dots_pointing_upwards_below": ["\u0758"],
18744 "small_tah_below": ["\u076E"],
18745 "small_tah_two_dots": ["\u076F"],
18746 "small_tah_above": ["\u0772"],
18747 "indic_four_below": ["\u077C"],
18748 "isolated": "\uFEA1",
18750 "initial": "\uFEA3",
18754 "normal": ["\u062E"],
18755 "isolated": "\uFEA5",
18757 "initial": "\uFEA7",
18761 "normal": ["\u062F"],
18762 "ring": ["\u0689"],
18763 "dot_below": ["\u068A"],
18764 "dot_below_small_tah": ["\u068B"],
18765 "three_dots_above_downwards": ["\u068F"],
18766 "four_dots_above": ["\u0690"],
18767 "inverted_v": ["\u06EE"],
18768 "two_dots_vertically_below_small_tah": ["\u0759"],
18769 "inverted_small_v_below": ["\u075A"],
18770 "three_dots_below": ["\u08AE"],
18771 "isolated": "\uFEA9",
18775 "normal": ["\u0630"],
18776 "isolated": "\uFEAB",
18780 "normal": ["\u0631"],
18781 "small_v": ["\u0692"],
18782 "ring": ["\u0693"],
18783 "dot_below": ["\u0694"],
18784 "small_v_below": ["\u0695"],
18785 "dot_below_dot_above": ["\u0696"],
18786 "two_dots_above": ["\u0697"],
18787 "four_dots_above": ["\u0699"],
18788 "inverted_v": ["\u06EF"],
18789 "stroke": ["\u075B"],
18790 "two_dots_vertically_above": ["\u076B"],
18791 "hamza_above": ["\u076C"],
18792 "small_tah_two_dots": ["\u0771"],
18793 "loop": ["\u08AA"],
18794 "small_noon_above": ["\u08B9"],
18795 "isolated": "\uFEAD",
18799 "normal": ["\u0632"],
18800 "inverted_v_above": ["\u08B2"],
18801 "isolated": "\uFEAF",
18805 "normal": ["\u0633"],
18806 "dot_below_dot_above": ["\u069A"],
18807 "three_dots_below": ["\u069B"],
18808 "three_dots_below_three_dots_above": ["\u069C"],
18809 "four_dots_above": ["\u075C"],
18810 "two_dots_vertically_above": ["\u076D"],
18811 "small_tah_two_dots": ["\u0770"],
18812 "indic_four_above": ["\u077D"],
18813 "inverted_v": ["\u077E"],
18814 "isolated": "\uFEB1",
18816 "initial": "\uFEB3",
18820 "normal": ["\u0634"],
18821 "dot_below": ["\u06FA"],
18822 "isolated": "\uFEB5",
18824 "initial": "\uFEB7",
18828 "normal": ["\u0635"],
18829 "two_dots_below": ["\u069D"],
18830 "three_dots_above": ["\u069E"],
18831 "three_dots_below": ["\u08AF"],
18832 "isolated": "\uFEB9",
18834 "initial": "\uFEBB",
18838 "normal": ["\u0636"],
18839 "dot_below": ["\u06FB"],
18840 "isolated": "\uFEBD",
18842 "initial": "\uFEBF",
18846 "normal": ["\u0637"],
18847 "three_dots_above": ["\u069F"],
18848 "two_dots_above": ["\u08A3"],
18849 "isolated": "\uFEC1",
18851 "initial": "\uFEC3",
18855 "normal": ["\u0638"],
18856 "isolated": "\uFEC5",
18858 "initial": "\uFEC7",
18862 "normal": ["\u0639"],
18863 "three_dots_above": ["\u06A0"],
18864 "two_dots_above": ["\u075D"],
18865 "three_dots_pointing_downwards_above": ["\u075E"],
18866 "two_dots_vertically_above": ["\u075F"],
18867 "three_dots_below": ["\u08B3"],
18868 "isolated": "\uFEC9",
18870 "initial": "\uFECB",
18874 "normal": ["\u063A"],
18875 "dot_below": ["\u06FC"],
18876 "isolated": "\uFECD",
18878 "initial": "\uFECF",
18882 "normal": ["\u0641"],
18883 "dotless": ["\u06A1"],
18884 "dot_moved_below": ["\u06A2"],
18885 "dot_below": ["\u06A3"],
18886 "three_dots_below": ["\u06A5"],
18887 "two_dots_below": ["\u0760"],
18888 "three_dots_pointing_upwards_below": ["\u0761"],
18889 "dot_below_three_dots_above": ["\u08A4"],
18890 "isolated": "\uFED1",
18892 "initial": "\uFED3",
18896 "normal": ["\u0642"],
18897 "dotless": ["\u066F"],
18898 "dot_above": ["\u06A7"],
18899 "three_dots_above": ["\u06A8"],
18900 "dot_below": ["\u08A5"],
18901 "isolated": "\uFED5",
18903 "initial": "\uFED7",
18907 "normal": ["\u0643"],
18908 "swash": ["\u06AA"],
18909 "ring": ["\u06AB"],
18910 "dot_above": ["\u06AC"],
18911 "three_dots_below": ["\u06AE"],
18912 "two_dots_above": ["\u077F"],
18913 "dot_below": ["\u08B4"],
18914 "isolated": "\uFED9",
18916 "initial": "\uFEDB",
18920 "normal": ["\u0644"],
18921 "small_v": ["\u06B5"],
18922 "dot_above": ["\u06B6"],
18923 "three_dots_above": ["\u06B7"],
18924 "three_dots_below": ["\u06B8"],
18926 "double_bar": ["\u08A6"],
18927 "isolated": "\uFEDD",
18929 "initial": "\uFEDF",
18933 "normal": ["\u0645"],
18934 "dot_above": ["\u0765"],
18935 "dot_below": ["\u0766"],
18936 "three_dots_above": ["\u08A7"],
18937 "isolated": "\uFEE1",
18939 "initial": "\uFEE3",
18943 "normal": ["\u0646"],
18944 "dot_below": ["\u06B9"],
18945 "ring": ["\u06BC"],
18946 "three_dots_above": ["\u06BD"],
18947 "two_dots_below": ["\u0767"],
18948 "small_tah": ["\u0768"],
18949 "small_v": ["\u0769"],
18950 "isolated": "\uFEE5",
18952 "initial": "\uFEE7",
18956 "normal": ["\u0647"],
18957 "isolated": "\uFEE9",
18959 "initial": "\uFEEB",
18963 "normal": ["\u0648"],
18965 "normal": ["\u0624", "\u0648\u0654"],
18966 "isolated": "\uFE85",
18969 "high_hamza": ["\u0676", "\u0648\u0674"],
18970 "ring": ["\u06C4"],
18971 "two_dots_above": ["\u06CA"],
18972 "dot_above": ["\u06CF"],
18973 "indic_two_above": ["\u0778"],
18974 "indic_three_above": ["\u0779"],
18975 "dot_within": ["\u08AB"],
18976 "isolated": "\uFEED",
18980 "normal": ["\u0649"],
18981 "hamza_above": ["\u0626", "\u064A\u0654"],
18982 "initial": "\uFBE8",
18983 "medial": "\uFBE9",
18984 "isolated": "\uFEEF",
18988 "normal": ["\u064A"],
18990 "normal": ["\u0626", "\u0649\u0654"],
18991 "isolated": "\uFE89",
18993 "initial": "\uFE8B",
18996 "two_dots_below_hamza_above": ["\u08A8"],
18997 "high_hamza": ["\u0678", "\u064A\u0674"],
18998 "tail": ["\u06CD"],
18999 "small_v": ["\u06CE"],
19000 "three_dots_below": ["\u06D1"],
19001 "two_dots_below_dot_above": ["\u08A9"],
19002 "two_dots_below_small_noon_above": ["\u08BA"],
19003 "isolated": "\uFEF1",
19005 "initial": "\uFEF3",
19009 "normal": ["\u0679"],
19010 "isolated": "\uFB66",
19012 "initial": "\uFB68",
19016 "normal": ["\u067A"],
19017 "isolated": "\uFB5E",
19019 "initial": "\uFB60",
19023 "normal": ["\u067B"],
19024 "isolated": "\uFB52",
19026 "initial": "\uFB54",
19030 "normal": ["\u067E"],
19031 "small_meem_above": ["\u08B7"],
19032 "isolated": "\uFB56",
19034 "initial": "\uFB58",
19038 "normal": ["\u067F"],
19039 "isolated": "\uFB62",
19041 "initial": "\uFB64",
19045 "normal": ["\u0680"],
19046 "isolated": "\uFB5A",
19048 "initial": "\uFB5C",
19052 "normal": ["\u0683"],
19053 "isolated": "\uFB76",
19055 "initial": "\uFB78",
19059 "normal": ["\u0684"],
19060 "isolated": "\uFB72",
19062 "initial": "\uFB74",
19066 "normal": ["\u0686"],
19067 "dot_above": ["\u06BF"],
19068 "isolated": "\uFB7A",
19070 "initial": "\uFB7C",
19074 "normal": ["\u0687"],
19075 "isolated": "\uFB7E",
19077 "initial": "\uFB80",
19081 "normal": ["\u0688"],
19082 "isolated": "\uFB88",
19086 "normal": ["\u068C"],
19087 "isolated": "\uFB84",
19091 "normal": ["\u068D"],
19092 "isolated": "\uFB82",
19096 "normal": ["\u068F", "\u068E"],
19097 "isolated": "\uFB86",
19101 "normal": ["\u0691"],
19102 "isolated": "\uFB8C",
19106 "normal": ["\u0698"],
19107 "isolated": "\uFB8A",
19111 "normal": ["\u06A4"],
19112 "isolated": "\uFB6A",
19114 "initial": "\uFB6C",
19118 "normal": ["\u06A6"],
19119 "isolated": "\uFB6E",
19121 "initial": "\uFB70",
19125 "normal": ["\u06A9"],
19126 "dot_above": ["\u0762"],
19127 "three_dots_above": ["\u0763"],
19128 "three_dots_pointing_upwards_below": ["\u0764"],
19129 "isolated": "\uFB8E",
19131 "initial": "\uFB90",
19135 "normal": ["\u06AD"],
19136 "isolated": "\uFBD3",
19138 "initial": "\uFBD5",
19142 "normal": ["\u06AF"],
19143 "ring": ["\u06B0"],
19144 "two_dots_below": ["\u06B2"],
19145 "three_dots_above": ["\u06B4"],
19146 "inverted_stroke": ["\u08B0"],
19147 "isolated": "\uFB92",
19149 "initial": "\uFB94",
19153 "normal": ["\u06B1"],
19154 "isolated": "\uFB9A",
19156 "initial": "\uFB9C",
19160 "normal": ["\u06B3"],
19161 "isolated": "\uFB96",
19163 "initial": "\uFB98",
19167 "normal": ["\u06BA"],
19168 "isolated": "\uFB9E",
19172 "normal": ["\u06BB"],
19173 "isolated": "\uFBA0",
19175 "initial": "\uFBA2",
19178 "heh doachashmee": {
19179 "normal": ["\u06BE"],
19180 "isolated": "\uFBAA",
19182 "initial": "\uFBAC",
19186 "normal": ["\u06C1"],
19187 "hamza_above": ["\u06C1\u0654", "\u06C2"],
19188 "isolated": "\uFBA6",
19190 "initial": "\uFBA8",
19193 "teh marbuta goal": {
19194 "normal": ["\u06C3"]
19197 "normal": ["\u06C5"],
19198 "isolated": "\uFBE0",
19202 "normal": ["\u06C6"],
19203 "isolated": "\uFBD9",
19207 "normal": ["\u06C7"],
19209 "normal": ["\u0677", "\u06C7\u0674"],
19210 "isolated": "\uFBDD"
19212 "isolated": "\uFBD7",
19216 "normal": ["\u06C8"],
19217 "isolated": "\uFBDB",
19221 "normal": ["\u06C9"],
19222 "isolated": "\uFBE2",
19226 "normal": ["\u06CB"],
19227 "isolated": "\uFBDE",
19231 "normal": ["\u06CC"],
19232 "indic_two_above": ["\u0775"],
19233 "indic_three_above": ["\u0776"],
19234 "indic_four_above": ["\u0777"],
19235 "isolated": "\uFBFC",
19237 "initial": "\uFBFE",
19241 "normal": ["\u06D0"],
19242 "isolated": "\uFBE4",
19244 "initial": "\uFBE6",
19248 "normal": ["\u06D2"],
19250 "normal": ["\u06D2\u0654", "\u06D3"],
19251 "isolated": "\uFBB0",
19254 "indic_two_above": ["\u077A"],
19255 "indic_three_above": ["\u077B"],
19256 "isolated": "\uFBAE",
19260 "normal": ["\u06D5"],
19261 "isolated": "\u06D5",
19264 "normal": ["\u06C0", "\u06D5\u0654"],
19265 "isolated": "\uFBA4",
19270 "normal": ["\u08AC"]
19273 "normal": ["\u08AD"]
19276 "normal": ["\u08B1"]
19279 "normal": ["\u08BB"]
19282 "normal": ["\u08BC"]
19285 "normal": ["\u08BD"]
19289 unicodeArabic["default"] = arabicReference;
19291 var unicodeLigatures = {};
19293 Object.defineProperty(unicodeLigatures, "__esModule", {
19296 var ligatureReference = {
19298 "isolated": "\uFBEA",
19302 "isolated": "\uFBEC",
19306 "isolated": "\uFBEE",
19310 "isolated": "\uFBF0",
19314 "isolated": "\uFBF2",
19318 "isolated": "\uFBF4",
19322 "isolated": "\uFBF6",
19324 "initial": "\uFBF8"
19327 "uighur_kirghiz": {
19328 "isolated": "\uFBF9",
19330 "initial": "\uFBFB"
19332 "isolated": "\uFC03",
19336 "isolated": "\uFC00",
19337 "initial": "\uFC97"
19340 "isolated": "\uFC01",
19341 "initial": "\uFC98"
19344 "isolated": "\uFC02",
19346 "initial": "\uFC9A",
19350 "isolated": "\uFC04",
19354 "isolated": "\uFC05",
19355 "initial": "\uFC9C"
19358 "isolated": "\uFC06",
19359 "initial": "\uFC9D"
19362 "isolated": "\uFC07",
19363 "initial": "\uFC9E"
19366 "isolated": "\uFC08",
19368 "initial": "\uFC9F",
19372 "isolated": "\uFC09",
19376 "isolated": "\uFC0A",
19380 "isolated": "\uFC0B",
19381 "initial": "\uFCA1"
19384 "isolated": "\uFC0C",
19385 "initial": "\uFCA2"
19388 "isolated": "\uFC0D",
19389 "initial": "\uFCA3"
19392 "isolated": "\uFC0E",
19394 "initial": "\uFCA4",
19398 "isolated": "\uFC0F",
19402 "isolated": "\uFC10",
19406 "isolated": "\uFC11"
19409 "isolated": "\uFC12",
19411 "initial": "\uFCA6",
19415 "isolated": "\uFC13",
19419 "isolated": "\uFC14"
19422 "isolated": "\uFC15",
19423 "initial": "\uFCA7"
19426 "isolated": "\uFC16",
19427 "initial": "\uFCA8"
19430 "isolated": "\uFC17",
19431 "initial": "\uFCA9"
19434 "isolated": "\uFC18",
19435 "initial": "\uFCAA"
19438 "isolated": "\uFC19",
19439 "initial": "\uFCAB"
19442 "isolated": "\uFC1A"
19445 "isolated": "\uFC1B",
19446 "initial": "\uFCAC"
19449 "isolated": "\uFC1C",
19450 "initial": "\uFCAD",
19454 "isolated": "\uFC1D",
19455 "initial": "\uFCAE",
19459 "isolated": "\uFC1E",
19460 "initial": "\uFCAF",
19464 "isolated": "\uFC1F",
19465 "initial": "\uFCB0",
19469 "isolated": "\uFC20",
19470 "initial": "\uFCB1"
19473 "isolated": "\uFC21",
19474 "initial": "\uFCB3"
19477 "isolated": "\uFC22",
19478 "initial": "\uFCB4"
19481 "isolated": "\uFC23",
19482 "initial": "\uFCB5"
19485 "isolated": "\uFC24",
19486 "initial": "\uFCB6"
19489 "isolated": "\uFC25",
19490 "initial": "\uFCB7"
19493 "isolated": "\uFC26",
19494 "initial": "\uFCB8"
19497 "isolated": "\uFC27",
19498 "initial": "\uFD33",
19502 "isolated": "\uFC28",
19503 "initial": "\uFCB9",
19507 "isolated": "\uFC29",
19508 "initial": "\uFCBA"
19511 "isolated": "\uFC2A",
19512 "initial": "\uFCBB"
19515 "isolated": "\uFC2B",
19516 "initial": "\uFCBC"
19519 "isolated": "\uFC2C",
19520 "initial": "\uFCBD"
19523 "isolated": "\uFC2D",
19524 "initial": "\uFCBE"
19527 "isolated": "\uFC2E",
19528 "initial": "\uFCBF"
19531 "isolated": "\uFC2F",
19532 "initial": "\uFCC0"
19535 "isolated": "\uFC30",
19536 "initial": "\uFCC1"
19539 "isolated": "\uFC31",
19543 "isolated": "\uFC32",
19547 "isolated": "\uFC33",
19548 "initial": "\uFCC2"
19551 "isolated": "\uFC34",
19552 "initial": "\uFCC3"
19555 "isolated": "\uFC35",
19559 "isolated": "\uFC36",
19563 "isolated": "\uFC37",
19567 "isolated": "\uFC38",
19568 "initial": "\uFCC4"
19571 "isolated": "\uFC39",
19572 "initial": "\uFCC5"
19575 "isolated": "\uFC3A",
19576 "initial": "\uFCC6"
19579 "isolated": "\uFC3B",
19581 "initial": "\uFCC7",
19585 "isolated": "\uFC3C",
19587 "initial": "\uFCC8",
19591 "isolated": "\uFC3D",
19595 "isolated": "\uFC3E",
19599 "isolated": "\uFC3F",
19600 "initial": "\uFCC9"
19603 "isolated": "\uFC40",
19604 "initial": "\uFCCA"
19607 "isolated": "\uFC41",
19608 "initial": "\uFCCB"
19611 "isolated": "\uFC42",
19613 "initial": "\uFCCC",
19617 "isolated": "\uFC43",
19621 "isolated": "\uFC44",
19625 "isolated": "\uFC45",
19626 "initial": "\uFCCE"
19629 "isolated": "\uFC46",
19630 "initial": "\uFCCF"
19633 "isolated": "\uFC47",
19634 "initial": "\uFCD0"
19637 "isolated": "\uFC48",
19639 "initial": "\uFCD1"
19642 "isolated": "\uFC49"
19645 "isolated": "\uFC4A"
19648 "isolated": "\uFC4B",
19649 "initial": "\uFCD2"
19652 "isolated": "\uFC4C",
19653 "initial": "\uFCD3"
19656 "isolated": "\uFC4D",
19657 "initial": "\uFCD4"
19660 "isolated": "\uFC4E",
19662 "initial": "\uFCD5",
19666 "isolated": "\uFC4F",
19670 "isolated": "\uFC50",
19674 "isolated": "\uFC51",
19675 "initial": "\uFCD7"
19678 "isolated": "\uFC52",
19679 "initial": "\uFCD8"
19682 "isolated": "\uFC53"
19685 "isolated": "\uFC54"
19688 "isolated": "\uFC55",
19689 "initial": "\uFCDA"
19692 "isolated": "\uFC56",
19693 "initial": "\uFCDB"
19696 "isolated": "\uFC57",
19697 "initial": "\uFCDC"
19700 "isolated": "\uFC58",
19702 "initial": "\uFCDD",
19706 "isolated": "\uFC59",
19710 "isolated": "\uFC5A",
19714 "isolated": "\uFC5B"
19717 "isolated": "\uFC5C"
19720 "isolated": "\uFC5D",
19724 "isolated": "\uFC5E"
19727 "isolated": "\uFC5F"
19730 "isolated": "\uFC60"
19733 "isolated": "\uFC61"
19736 "isolated": "\uFC62"
19739 "isolated": "\uFC63"
19802 "initial": "\uFC99"
19805 "initial": "\uFC9B",
19809 "initial": "\uFCA0",
19813 "initial": "\uFCA5",
19817 "initial": "\uFCB2"
19820 "initial": "\uFCCD"
19823 "initial": "\uFCD6",
19827 "initial": "\uFCD9"
19830 "initial": "\uFCDE",
19837 "medial": "\uFCE8",
19838 "initial": "\uFD31"
19841 "medial": "\uFCE9",
19842 "isolated": "\uFD0C",
19844 "initial": "\uFD30"
19847 "medial": "\uFCEA",
19848 "initial": "\uFD32"
19850 "\u0640\u064E\u0651": {
19853 "\u0640\u064F\u0651": {
19856 "\u0640\u0650\u0651": {
19860 "isolated": "\uFCF5",
19864 "isolated": "\uFCF6",
19868 "isolated": "\uFCF7",
19872 "isolated": "\uFCF8",
19876 "isolated": "\uFCF9",
19880 "isolated": "\uFCFA",
19884 "isolated": "\uFCFB"
19887 "isolated": "\uFCFC",
19891 "isolated": "\uFCFD",
19895 "isolated": "\uFCFE",
19899 "isolated": "\uFCFF",
19903 "isolated": "\uFD00",
19907 "isolated": "\uFD01",
19911 "isolated": "\uFD02",
19915 "isolated": "\uFD03",
19919 "isolated": "\uFD04",
19923 "isolated": "\uFD05",
19927 "isolated": "\uFD06",
19931 "isolated": "\uFD07",
19935 "isolated": "\uFD08",
19939 "isolated": "\uFD09",
19941 "initial": "\uFD2D",
19945 "isolated": "\uFD0A",
19947 "initial": "\uFD2E",
19951 "isolated": "\uFD0B",
19953 "initial": "\uFD2F",
19957 "isolated": "\uFD0D",
19961 "isolated": "\uFD0E",
19965 "isolated": "\uFD0F",
19969 "isolated": "\uFD10",
19975 "\u062A\u062C\u0645": {
19976 "initial": "\uFD50"
19978 "\u062A\u062D\u062C": {
19980 "initial": "\uFD52"
19982 "\u062A\u062D\u0645": {
19983 "initial": "\uFD53"
19985 "\u062A\u062E\u0645": {
19986 "initial": "\uFD54"
19988 "\u062A\u0645\u062C": {
19989 "initial": "\uFD55"
19991 "\u062A\u0645\u062D": {
19992 "initial": "\uFD56"
19994 "\u062A\u0645\u062E": {
19995 "initial": "\uFD57"
19997 "\u062C\u0645\u062D": {
19999 "initial": "\uFD59"
20001 "\u062D\u0645\u064A": {
20004 "\u062D\u0645\u0649": {
20007 "\u0633\u062D\u062C": {
20008 "initial": "\uFD5C"
20010 "\u0633\u062C\u062D": {
20011 "initial": "\uFD5D"
20013 "\u0633\u062C\u0649": {
20016 "\u0633\u0645\u062D": {
20018 "initial": "\uFD60"
20020 "\u0633\u0645\u062C": {
20021 "initial": "\uFD61"
20023 "\u0633\u0645\u0645": {
20025 "initial": "\uFD63"
20027 "\u0635\u062D\u062D": {
20029 "initial": "\uFD65"
20031 "\u0635\u0645\u0645": {
20033 "initial": "\uFDC5"
20035 "\u0634\u062D\u0645": {
20037 "initial": "\uFD68"
20039 "\u0634\u062C\u064A": {
20042 "\u0634\u0645\u062E": {
20044 "initial": "\uFD6B"
20046 "\u0634\u0645\u0645": {
20048 "initial": "\uFD6D"
20050 "\u0636\u062D\u0649": {
20053 "\u0636\u062E\u0645": {
20055 "initial": "\uFD70"
20057 "\u0636\u0645\u062D": {
20060 "\u0637\u0645\u062D": {
20061 "initial": "\uFD72"
20063 "\u0637\u0645\u0645": {
20064 "initial": "\uFD73"
20066 "\u0637\u0645\u064A": {
20069 "\u0639\u062C\u0645": {
20071 "initial": "\uFDC4"
20073 "\u0639\u0645\u0645": {
20075 "initial": "\uFD77"
20077 "\u0639\u0645\u0649": {
20080 "\u063A\u0645\u0645": {
20083 "\u063A\u0645\u064A": {
20086 "\u063A\u0645\u0649": {
20089 "\u0641\u062E\u0645": {
20091 "initial": "\uFD7D"
20093 "\u0642\u0645\u062D": {
20095 "initial": "\uFDB4"
20097 "\u0642\u0645\u0645": {
20100 "\u0644\u062D\u0645": {
20102 "initial": "\uFDB5"
20104 "\u0644\u062D\u064A": {
20107 "\u0644\u062D\u0649": {
20110 "\u0644\u062C\u062C": {
20111 "initial": "\uFD83",
20114 "\u0644\u062E\u0645": {
20116 "initial": "\uFD86"
20118 "\u0644\u0645\u062D": {
20120 "initial": "\uFD88"
20122 "\u0645\u062D\u062C": {
20123 "initial": "\uFD89"
20125 "\u0645\u062D\u0645": {
20126 "initial": "\uFD8A"
20128 "\u0645\u062D\u064A": {
20131 "\u0645\u062C\u062D": {
20132 "initial": "\uFD8C"
20134 "\u0645\u062C\u0645": {
20135 "initial": "\uFD8D"
20137 "\u0645\u062E\u062C": {
20138 "initial": "\uFD8E"
20140 "\u0645\u062E\u0645": {
20141 "initial": "\uFD8F"
20143 "\u0645\u062C\u062E": {
20144 "initial": "\uFD92"
20146 "\u0647\u0645\u062C": {
20147 "initial": "\uFD93"
20149 "\u0647\u0645\u0645": {
20150 "initial": "\uFD94"
20152 "\u0646\u062D\u0645": {
20153 "initial": "\uFD95"
20155 "\u0646\u062D\u0649": {
20158 "\u0646\u062C\u0645": {
20160 "initial": "\uFD98"
20162 "\u0646\u062C\u0649": {
20165 "\u0646\u0645\u064A": {
20168 "\u0646\u0645\u0649": {
20171 "\u064A\u0645\u0645": {
20173 "initial": "\uFD9D"
20175 "\u0628\u062E\u064A": {
20178 "\u062A\u062C\u064A": {
20181 "\u062A\u062C\u0649": {
20184 "\u062A\u062E\u064A": {
20187 "\u062A\u062E\u0649": {
20190 "\u062A\u0645\u064A": {
20193 "\u062A\u0645\u0649": {
20196 "\u062C\u0645\u064A": {
20199 "\u062C\u062D\u0649": {
20202 "\u062C\u0645\u0649": {
20205 "\u0633\u062E\u0649": {
20208 "\u0635\u062D\u064A": {
20211 "\u0634\u062D\u064A": {
20214 "\u0636\u062D\u064A": {
20217 "\u0644\u062C\u064A": {
20220 "\u0644\u0645\u064A": {
20223 "\u064A\u062D\u064A": {
20226 "\u064A\u062C\u064A": {
20229 "\u064A\u0645\u064A": {
20232 "\u0645\u0645\u064A": {
20235 "\u0642\u0645\u064A": {
20238 "\u0646\u062D\u064A": {
20241 "\u0639\u0645\u064A": {
20244 "\u0643\u0645\u064A": {
20247 "\u0646\u062C\u062D": {
20248 "initial": "\uFDB8",
20251 "\u0645\u062E\u064A": {
20254 "\u0644\u062C\u0645": {
20255 "initial": "\uFDBA",
20258 "\u0643\u0645\u0645": {
20260 "initial": "\uFDC3"
20262 "\u062C\u062D\u064A": {
20265 "\u062D\u062C\u064A": {
20268 "\u0645\u062C\u064A": {
20271 "\u0641\u0645\u064A": {
20274 "\u0628\u062D\u064A": {
20277 "\u0633\u062E\u064A": {
20280 "\u0646\u062C\u064A": {
20284 "isolated": "\uFEF5",
20288 "isolated": "\uFEF7",
20292 "isolated": "\uFEF9",
20296 "isolated": "\uFEFB",
20300 "\u0635\u0644\u06D2": "\uFDF0",
20301 "\u0642\u0644\u06D2": "\uFDF1",
20302 "\u0627\u0644\u0644\u0647": "\uFDF2",
20303 "\u0627\u0643\u0628\u0631": "\uFDF3",
20304 "\u0645\u062D\u0645\u062F": "\uFDF4",
20305 "\u0635\u0644\u0639\u0645": "\uFDF5",
20306 "\u0631\u0633\u0648\u0644": "\uFDF6",
20307 "\u0639\u0644\u064A\u0647": "\uFDF7",
20308 "\u0648\u0633\u0644\u0645": "\uFDF8",
20309 "\u0635\u0644\u0649": "\uFDF9",
20310 "\u0635\u0644\u0649\u0627\u0644\u0644\u0647\u0639\u0644\u064A\u0647\u0648\u0633\u0644\u0645": "\uFDFA",
20311 "\u062C\u0644\u062C\u0644\u0627\u0644\u0647": "\uFDFB",
20312 "\u0631\u06CC\u0627\u0644": "\uFDFC"
20316 unicodeLigatures["default"] = ligatureReference;
20318 Object.defineProperty(reference, "__esModule", {
20321 var unicode_arabic_1$3 = unicodeArabic;
20322 var unicode_ligatures_1$2 = unicodeLigatures;
20323 var letterList = Object.keys(unicode_arabic_1$3["default"]);
20324 reference.letterList = letterList;
20325 var ligatureList = Object.keys(unicode_ligatures_1$2["default"]);
20326 reference.ligatureList = ligatureList;
20327 var ligatureWordList = Object.keys(unicode_ligatures_1$2["default"].words);
20328 reference.ligatureWordList = ligatureWordList;
20329 var lams = "\u0644\u06B5\u06B6\u06B7\u06B8";
20330 reference.lams = lams;
20331 var alefs = "\u0627\u0622\u0623\u0625\u0671\u0672\u0673\u0675\u0773\u0774";
20332 reference.alefs = alefs; // for (var l = 1; l < lams.length; l++) {
20333 // console.log('-');
20334 // for (var a = 0; a < alefs.length; a++) {
20335 // console.log(a + ': ' + lams[l] + alefs[a]);
20339 var tashkeel = "\u0605\u0640\u0670\u0674\u06DF\u06E7\u06E8";
20340 reference.tashkeel = tashkeel;
20342 function addToTashkeel(start, finish) {
20343 for (var i = start; i <= finish; i++) {
20344 reference.tashkeel = tashkeel += String.fromCharCode(i);
20348 addToTashkeel(0x0610, 0x061A);
20349 addToTashkeel(0x064B, 0x065F);
20350 addToTashkeel(0x06D6, 0x06DC);
20351 addToTashkeel(0x06E0, 0x06E4);
20352 addToTashkeel(0x06EA, 0x06ED);
20353 addToTashkeel(0x08D3, 0x08E1);
20354 addToTashkeel(0x08E3, 0x08FF);
20355 addToTashkeel(0xFE70, 0xFE7F);
20356 var lineBreakers = "\u0627\u0629\u0648\u06C0\u06CF\u06FD\u06FE\u076B\u076C\u0771\u0773\u0774\u0778\u0779\u08E2\u08B1\u08B2\u08B9";
20357 reference.lineBreakers = lineBreakers;
20359 function addToLineBreakers(start, finish) {
20360 for (var i = start; i <= finish; i++) {
20361 reference.lineBreakers = lineBreakers += String.fromCharCode(i);
20365 addToLineBreakers(0x0600, 0x061F); // it's OK to include tashkeel in this range as it is ignored
20367 addToLineBreakers(0x0621, 0x0625);
20368 addToLineBreakers(0x062F, 0x0632);
20369 addToLineBreakers(0x0660, 0x066D); // numerals, math
20371 addToLineBreakers(0x0671, 0x0677);
20372 addToLineBreakers(0x0688, 0x0699);
20373 addToLineBreakers(0x06C3, 0x06CB);
20374 addToLineBreakers(0x06D2, 0x06F9);
20375 addToLineBreakers(0x0759, 0x075B);
20376 addToLineBreakers(0x08AA, 0x08AE);
20377 addToLineBreakers(0xFB50, 0xFDFD); // presentation forms look like they could connect, but never do
20378 // Presentation Forms A includes diacritics but they are meant to stand alone
20380 addToLineBreakers(0xFE80, 0xFEFC); // presentation forms look like they could connect, but never do
20383 addToLineBreakers(0x10E60, 0x10E7F);
20384 addToLineBreakers(0x1EC70, 0x1ECBF);
20385 addToLineBreakers(0x1EE00, 0x1EEFF);
20387 Object.defineProperty(GlyphSplitter$1, "__esModule", {
20390 var isArabic_1$6 = isArabic$1;
20391 var reference_1$5 = reference;
20393 function GlyphSplitter(word) {
20395 var lastLetter = '';
20396 word.split('').forEach(function (letter) {
20397 if (isArabic_1$6.isArabic(letter)) {
20398 if (reference_1$5.tashkeel.indexOf(letter) > -1) {
20399 letters[letters.length - 1] += letter;
20400 } else if (lastLetter.length && (reference_1$5.lams.indexOf(lastLetter) === 0 && reference_1$5.alefs.indexOf(letter) > -1 || reference_1$5.lams.indexOf(lastLetter) > 0 && reference_1$5.alefs.indexOf(letter) === 0)) {
20402 letters[letters.length - 1] += letter;
20404 letters.push(letter);
20407 letters.push(letter);
20410 if (reference_1$5.tashkeel.indexOf(letter) === -1) {
20411 lastLetter = letter;
20417 GlyphSplitter$1.GlyphSplitter = GlyphSplitter;
20419 var BaselineSplitter$1 = {};
20421 Object.defineProperty(BaselineSplitter$1, "__esModule", {
20424 var isArabic_1$5 = isArabic$1;
20425 var reference_1$4 = reference;
20427 function BaselineSplitter(word) {
20429 var lastLetter = '';
20430 word.split('').forEach(function (letter) {
20431 if (isArabic_1$5.isArabic(letter) && isArabic_1$5.isArabic(lastLetter)) {
20432 if (lastLetter.length && reference_1$4.tashkeel.indexOf(letter) > -1) {
20433 letters[letters.length - 1] += letter;
20434 } else if (reference_1$4.lineBreakers.indexOf(lastLetter) > -1) {
20435 letters.push(letter);
20437 letters[letters.length - 1] += letter;
20440 letters.push(letter);
20443 if (reference_1$4.tashkeel.indexOf(letter) === -1) {
20444 // don't allow tashkeel to hide line break
20445 lastLetter = letter;
20451 BaselineSplitter$1.BaselineSplitter = BaselineSplitter;
20453 var Normalization = {};
20455 Object.defineProperty(Normalization, "__esModule", {
20458 var unicode_arabic_1$2 = unicodeArabic;
20459 var unicode_ligatures_1$1 = unicodeLigatures;
20460 var isArabic_1$4 = isArabic$1;
20461 var reference_1$3 = reference;
20463 function Normal(word, breakPresentationForm) {
20464 // default is to turn initial/isolated/medial/final presentation form to generic
20465 if (typeof breakPresentationForm === 'undefined') {
20466 breakPresentationForm = true;
20469 var returnable = '';
20470 word.split('').forEach(function (letter) {
20471 if (!isArabic_1$4.isArabic(letter)) {
20472 returnable += letter;
20476 for (var w = 0; w < reference_1$3.letterList.length; w++) {
20477 // ok so we are checking this potential lettertron
20478 var letterForms = unicode_arabic_1$2["default"][reference_1$3.letterList[w]];
20479 var versions = Object.keys(letterForms);
20481 for (var v = 0; v < versions.length; v++) {
20482 var localVersion = letterForms[versions[v]];
20484 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20485 // look at this embedded object
20486 var embeddedForms = Object.keys(localVersion);
20488 for (var ef = 0; ef < embeddedForms.length; ef++) {
20489 var form = localVersion[embeddedForms[ef]];
20491 if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20493 // console.log('embedded match');
20494 if (form === letter) {
20496 if (breakPresentationForm && localVersion['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(embeddedForms[ef]) > -1) {
20497 // replace presentation form
20498 // console.log('keeping normal form of the letter');
20499 if (_typeof(localVersion['normal']) === 'object') {
20500 returnable += localVersion['normal'][0];
20502 returnable += localVersion['normal'];
20506 } // console.log('keeping this letter');
20509 returnable += letter;
20511 } else if (_typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20513 returnable += form[0]; // console.log('added the first letter from the same array');
20519 } else if (localVersion === letter) {
20521 if (breakPresentationForm && letterForms['normal'] && ['isolated', 'initial', 'medial', 'final'].indexOf(versions[v]) > -1) {
20522 // replace presentation form
20523 // console.log('keeping normal form of the letter');
20524 if (_typeof(letterForms['normal']) === 'object') {
20525 returnable += letterForms['normal'][0];
20527 returnable += letterForms['normal'];
20531 } // console.log('keeping this letter');
20534 returnable += letter;
20536 } else if (_typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20538 returnable += localVersion[0]; // console.log('added the first letter from the same array');
20546 for (var v2 = 0; v2 < reference_1$3.ligatureList.length; v2++) {
20547 var normalForm = reference_1$3.ligatureList[v2];
20549 if (normalForm !== 'words') {
20550 var ligForms = Object.keys(unicode_ligatures_1$1["default"][normalForm]);
20552 for (var f = 0; f < ligForms.length; f++) {
20553 if (unicode_ligatures_1$1["default"][normalForm][ligForms[f]] === letter) {
20554 returnable += normalForm;
20559 } // try words ligatures
20562 for (var v3 = 0; v3 < reference_1$3.ligatureWordList.length; v3++) {
20563 var _normalForm = reference_1$3.ligatureWordList[v3];
20565 if (unicode_ligatures_1$1["default"].words[_normalForm] === letter) {
20566 returnable += _normalForm;
20571 returnable += letter; // console.log('kept the letter')
20576 Normalization.Normal = Normal;
20578 var CharShaper$1 = {};
20580 Object.defineProperty(CharShaper$1, "__esModule", {
20583 var unicode_arabic_1$1 = unicodeArabic;
20584 var isArabic_1$3 = isArabic$1;
20585 var reference_1$2 = reference;
20587 function CharShaper(letter, form) {
20588 if (!isArabic_1$3.isArabic(letter)) {
20590 throw new Error('Not Arabic');
20593 if (letter === "\u0621") {
20598 for (var w = 0; w < reference_1$2.letterList.length; w++) {
20599 // ok so we are checking this potential lettertron
20600 var letterForms = unicode_arabic_1$1["default"][reference_1$2.letterList[w]];
20601 var versions = Object.keys(letterForms);
20603 for (var v = 0; v < versions.length; v++) {
20604 var localVersion = letterForms[versions[v]];
20606 if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20607 if (versions.indexOf(form) > -1) {
20608 return letterForms[form];
20610 } else if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20612 var embeddedVersions = Object.keys(localVersion);
20614 for (var ev = 0; ev < embeddedVersions.length; ev++) {
20615 if (localVersion[embeddedVersions[ev]] === letter || _typeof(localVersion[embeddedVersions[ev]]) === 'object' && localVersion[embeddedVersions[ev]].indexOf && localVersion[embeddedVersions[ev]].indexOf(letter) > -1) {
20616 if (embeddedVersions.indexOf(form) > -1) {
20617 return localVersion[form];
20626 CharShaper$1.CharShaper = CharShaper;
20628 var WordShaper$2 = {};
20630 Object.defineProperty(WordShaper$2, "__esModule", {
20633 var isArabic_1$2 = isArabic$1;
20634 var reference_1$1 = reference;
20635 var CharShaper_1$1 = CharShaper$1;
20636 var unicode_ligatures_1 = unicodeLigatures;
20638 function WordShaper$1(word) {
20639 var state = 'initial';
20642 for (var w = 0; w < word.length; w++) {
20643 var nextLetter = ' ';
20645 for (var nxw = w + 1; nxw < word.length; nxw++) {
20646 if (!isArabic_1$2.isArabic(word[nxw])) {
20650 if (reference_1$1.tashkeel.indexOf(word[nxw]) === -1) {
20651 nextLetter = word[nxw];
20656 if (!isArabic_1$2.isArabic(word[w]) || isArabic_1$2.isMath(word[w])) {
20657 // space or other non-Arabic
20660 } else if (reference_1$1.tashkeel.indexOf(word[w]) > -1) {
20661 // tashkeel - add without changing state
20663 } else if (nextLetter === ' ' || // last Arabic letter in this word
20664 reference_1$1.lineBreakers.indexOf(word[w]) > -1) {
20665 // the current letter is known to break lines
20666 output += CharShaper_1$1.CharShaper(word[w], state === 'initial' ? 'isolated' : 'final');
20668 } else if (reference_1$1.lams.indexOf(word[w]) > -1 && reference_1$1.alefs.indexOf(nextLetter) > -1) {
20669 // LA letters - advance an additional letter after this
20670 output += unicode_ligatures_1["default"][word[w] + nextLetter][state === 'initial' ? 'isolated' : 'final'];
20672 while (word[w] !== nextLetter) {
20678 output += CharShaper_1$1.CharShaper(word[w], state);
20686 WordShaper$2.WordShaper = WordShaper$1;
20688 var ParentLetter$1 = {};
20690 Object.defineProperty(ParentLetter$1, "__esModule", {
20693 var unicode_arabic_1 = unicodeArabic;
20694 var isArabic_1$1 = isArabic$1;
20695 var reference_1 = reference;
20697 function ParentLetter(letter) {
20698 if (!isArabic_1$1.isArabic(letter)) {
20699 throw new Error('Not an Arabic letter');
20702 for (var w = 0; w < reference_1.letterList.length; w++) {
20703 // ok so we are checking this potential lettertron
20704 var letterForms = unicode_arabic_1["default"][reference_1.letterList[w]];
20705 var versions = Object.keys(letterForms);
20707 for (var v = 0; v < versions.length; v++) {
20708 var localVersion = letterForms[versions[v]];
20710 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20711 // look at this embedded object
20712 var embeddedForms = Object.keys(localVersion);
20714 for (var ef = 0; ef < embeddedForms.length; ef++) {
20715 var form = localVersion[embeddedForms[ef]];
20717 if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20719 return localVersion;
20722 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20724 return letterForms;
20732 ParentLetter$1.ParentLetter = ParentLetter;
20734 function GrandparentLetter(letter) {
20735 if (!isArabic_1$1.isArabic(letter)) {
20736 throw new Error('Not an Arabic letter');
20739 for (var w = 0; w < reference_1.letterList.length; w++) {
20740 // ok so we are checking this potential lettertron
20741 var letterForms = unicode_arabic_1["default"][reference_1.letterList[w]];
20742 var versions = Object.keys(letterForms);
20744 for (var v = 0; v < versions.length; v++) {
20745 var localVersion = letterForms[versions[v]];
20747 if (_typeof(localVersion) === 'object' && typeof localVersion.indexOf === 'undefined') {
20748 // look at this embedded object
20749 var embeddedForms = Object.keys(localVersion);
20751 for (var ef = 0; ef < embeddedForms.length; ef++) {
20752 var form = localVersion[embeddedForms[ef]];
20754 if (form === letter || _typeof(form) === 'object' && form.indexOf && form.indexOf(letter) > -1) {
20756 return letterForms;
20759 } else if (localVersion === letter || _typeof(localVersion) === 'object' && localVersion.indexOf && localVersion.indexOf(letter) > -1) {
20761 return letterForms;
20769 ParentLetter$1.GrandparentLetter = GrandparentLetter;
20771 Object.defineProperty(lib, "__esModule", {
20774 var isArabic_1 = isArabic$1;
20775 lib.isArabic = isArabic_1.isArabic;
20776 var GlyphSplitter_1 = GlyphSplitter$1;
20777 lib.GlyphSplitter = GlyphSplitter_1.GlyphSplitter;
20778 var BaselineSplitter_1 = BaselineSplitter$1;
20779 lib.BaselineSplitter = BaselineSplitter_1.BaselineSplitter;
20780 var Normalization_1 = Normalization;
20781 lib.Normal = Normalization_1.Normal;
20782 var CharShaper_1 = CharShaper$1;
20783 lib.CharShaper = CharShaper_1.CharShaper;
20784 var WordShaper_1 = WordShaper$2;
20785 var WordShaper = lib.WordShaper = WordShaper_1.WordShaper;
20786 var ParentLetter_1 = ParentLetter$1;
20787 lib.ParentLetter = ParentLetter_1.ParentLetter;
20788 lib.GrandparentLetter = ParentLetter_1.GrandparentLetter;
20790 var rtlRegex = /[\u0590-\u05FF\u0600-\u06FF\u0750-\u07BF\u08A0–\u08BF]/;
20791 function fixRTLTextForSvg(inputText) {
20794 var arabicRegex = /[\u0600-\u06FF]/g;
20795 var arabicDiacritics = /[\u0610-\u061A\u064B-\u065F\u0670\u06D6-\u06ED]/g;
20796 var arabicMath = /[\u0660-\u066C\u06F0-\u06F9]+/g;
20797 var thaanaVowel = /[\u07A6-\u07B0]/;
20798 var hebrewSign = /[\u0591-\u05bd\u05bf\u05c1-\u05c5\u05c7]/; // Arabic word shaping
20800 if (arabicRegex.test(inputText)) {
20801 inputText = WordShaper(inputText);
20804 for (var n = 0; n < inputText.length; n++) {
20805 var c = inputText[n];
20807 if (arabicMath.test(c)) {
20808 // Arabic numbers go LTR
20809 ret += rtlBuffer.reverse().join('');
20812 if (rtlBuffer.length && arabicMath.test(rtlBuffer[rtlBuffer.length - 1])) {
20813 ret += rtlBuffer.reverse().join('');
20817 if ((thaanaVowel.test(c) || hebrewSign.test(c) || arabicDiacritics.test(c)) && rtlBuffer.length) {
20818 rtlBuffer[rtlBuffer.length - 1] += c;
20819 } else if (rtlRegex.test(c) // include Arabic presentation forms
20820 || c.charCodeAt(0) >= 64336 && c.charCodeAt(0) <= 65023 || c.charCodeAt(0) >= 65136 && c.charCodeAt(0) <= 65279) {
20822 } else if (c === ' ' && rtlBuffer.length) {
20823 // whitespace within RTL text
20824 rtlBuffer = [rtlBuffer.reverse().join('') + ' '];
20826 // non-RTL character
20827 ret += rtlBuffer.reverse().join('') + c;
20833 ret += rtlBuffer.reverse().join('');
20837 var DESCRIPTORS$1 = descriptors;
20838 var objectKeys = objectKeys$4;
20839 var toIndexedObject = toIndexedObject$b;
20840 var propertyIsEnumerable = objectPropertyIsEnumerable.f;
20842 // `Object.{ entries, values }` methods implementation
20843 var createMethod$1 = function (TO_ENTRIES) {
20844 return function (it) {
20845 var O = toIndexedObject(it);
20846 var keys = objectKeys(O);
20847 var length = keys.length;
20851 while (length > i) {
20853 if (!DESCRIPTORS$1 || propertyIsEnumerable.call(O, key)) {
20854 result.push(TO_ENTRIES ? [key, O[key]] : O[key]);
20861 var objectToArray = {
20862 // `Object.entries` method
20863 // https://tc39.es/ecma262/#sec-object.entries
20864 entries: createMethod$1(true),
20865 // `Object.values` method
20866 // https://tc39.es/ecma262/#sec-object.values
20867 values: createMethod$1(false)
20871 var $values = objectToArray.values;
20873 // `Object.values` method
20874 // https://tc39.es/ecma262/#sec-object.values
20875 $$k({ target: 'Object', stat: true }, {
20876 values: function values(O) {
20881 // https://github.com/openstreetmap/iD/issues/772
20882 // http://mathiasbynens.be/notes/localstorage-pattern#comment-9
20886 _storage = localStorage;
20887 } catch (e) {} // eslint-disable-line no-empty
20890 _storage = _storage || function () {
20893 getItem: function getItem(k) {
20896 setItem: function setItem(k, v) {
20899 removeItem: function removeItem(k) {
20900 return delete s[k];
20904 // corePreferences is an interface for persisting basic key-value strings
20905 // within and between iD sessions on the same site.
20909 * @param {string} k
20910 * @param {string?} v
20911 * @returns {boolean} true if the action succeeded
20915 function corePreferences(k, v) {
20917 if (arguments.length === 1) return _storage.getItem(k);else if (v === null) _storage.removeItem(k);else _storage.setItem(k, v);
20920 /* eslint-disable no-console */
20921 if (typeof console !== 'undefined') {
20922 console.error('localStorage quota exceeded');
20924 /* eslint-enable no-console */
20931 var vparse = {exports: {}};
20933 (function (module) {
20934 (function (window) {
20936 function parseVersion(v) {
20937 var m = v.replace(/[^0-9.]/g, '').match(/[0-9]*\.|[0-9]+/g) || [];
20944 v.isEmpty = !v.major && !v.minor && !v.patch && !v.build;
20945 v.parsed = [v.major, v.minor, v.patch, v.build];
20946 v.text = v.parsed.join('.');
20947 v.compare = compare;
20951 function compare(v) {
20952 if (typeof v === 'string') {
20953 v = parseVersion(v);
20956 for (var i = 0; i < 4; i++) {
20957 if (this.parsed[i] !== v.parsed[i]) {
20958 return this.parsed[i] > v.parsed[i] ? 1 : -1;
20964 /* istanbul ignore next */
20967 if (module && 'object' === 'object') {
20968 module.exports = parseVersion;
20970 window.parseVersion = parseVersion;
20972 })(commonjsGlobal);
20975 var parseVersion = vparse.exports;
20978 var version = "2.20.2";
20979 var description = "A friendly editor for OpenStreetMap";
20980 var main = "dist/iD.min.js";
20981 var repository = "github:openstreetmap/iD";
20982 var homepage = "https://github.com/openstreetmap/iD";
20983 var bugs = "https://github.com/openstreetmap/iD/issues";
20984 var keywords = ["editor","openstreetmap"];
20985 var license = "ISC";
20986 var scripts = {all:"npm-run-all -s clean build build:legacy dist",build:"npm-run-all -s build:css build:data build:dev","build:css":"node scripts/build_css.js","build:data":"shx mkdir -p dist/data && node scripts/build_data.js","build:dev":"rollup --config config/rollup.config.dev.js","build:legacy":"rollup --config config/rollup.config.legacy.js","build:stats":"rollup --config config/rollup.config.stats.js",clean:"shx rm -f dist/*.js dist/*.map dist/*.css dist/img/*.svg",dist:"npm-run-all -p dist:**","dist:mapillary":"shx mkdir -p dist/mapillary-js && shx cp -R node_modules/mapillary-js/dist/* dist/mapillary-js/","dist:pannellum":"shx mkdir -p dist/pannellum-streetside && shx cp -R node_modules/pannellum/build/* dist/pannellum-streetside/","dist:min:iD":"uglifyjs dist/iD.legacy.js --compress --mangle --output dist/iD.min.js","dist:svg:iD":"svg-sprite --symbol --symbol-dest . --shape-id-generator \"iD-%s\" --symbol-sprite dist/img/iD-sprite.svg \"svg/iD-sprite/**/*.svg\"","dist:svg:community":"svg-sprite --symbol --symbol-dest . --shape-id-generator \"community-%s\" --symbol-sprite dist/img/community-sprite.svg node_modules/osm-community-index/dist/img/*.svg","dist:svg:fa":"svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/fa-sprite.svg svg/fontawesome/*.svg","dist:svg:maki":"svg-sprite --symbol --symbol-dest . --shape-id-generator \"maki-%s\" --symbol-sprite dist/img/maki-sprite.svg node_modules/@mapbox/maki/icons/*.svg","dist:svg:mapillary:signs":"svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/mapillary-sprite.svg node_modules/mapillary_sprite_source/package_signs/*.svg","dist:svg:mapillary:objects":"svg-sprite --symbol --symbol-dest . --symbol-sprite dist/img/mapillary-object-sprite.svg node_modules/mapillary_sprite_source/package_objects/*.svg","dist:svg:temaki":"svg-sprite --symbol --symbol-dest . --shape-id-generator \"temaki-%s\" --symbol-sprite dist/img/temaki-sprite.svg node_modules/@ideditor/temaki/icons/*.svg",imagery:"node scripts/update_imagery.js",lint:"eslint scripts test/spec modules","lint:fix":"eslint scripts test/spec modules --fix",start:"npm-run-all -s build start:server",quickstart:"npm-run-all -s build:dev start:server","start:server":"node scripts/server.js",test:"npm-run-all -s lint build:css build:data build:legacy test:spec","test:spec":"phantomjs --web-security=no node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html spec",translations:"node scripts/update_locales.js"};
20987 var dependencies = {"@ideditor/country-coder":"~5.0.3","@ideditor/location-conflation":"~1.0.2","@mapbox/geojson-area":"^0.2.2","@mapbox/sexagesimal":"1.2.0","@mapbox/vector-tile":"^1.3.1","@tmcw/togeojson":"^4.5.0","@turf/bbox-clip":"^6.0.0","abortcontroller-polyfill":"^1.4.0","aes-js":"^3.1.2","alif-toolkit":"^1.2.9","core-js":"^3.6.5",diacritics:"1.3.0","fast-deep-equal":"~3.1.1","fast-json-stable-stringify":"2.1.0","lodash-es":"~4.17.15",marked:"~2.0.0","node-diff3":"2.1.0","osm-auth":"1.1.0",pannellum:"2.5.6",pbf:"^3.2.1","polygon-clipping":"~0.15.1",rbush:"3.0.1","whatwg-fetch":"^3.4.1","which-polygon":"2.2.0"};
20988 var devDependencies = {"@babel/core":"^7.11.6","@babel/preset-env":"^7.11.5","@fortawesome/fontawesome-svg-core":"^1.2.32","@fortawesome/free-brands-svg-icons":"~5.15.1","@fortawesome/free-regular-svg-icons":"~5.15.1","@fortawesome/free-solid-svg-icons":"~5.15.1","@ideditor/temaki":"~4.4.0","@mapbox/maki":"^6.0.0","@rollup/plugin-babel":"^5.2.1","@rollup/plugin-commonjs":"^21.0.0","@rollup/plugin-json":"^4.0.1","@rollup/plugin-node-resolve":"~13.0.5",autoprefixer:"^10.0.1",btoa:"^1.2.1",chai:"^4.1.0","cldr-core":"37.0.0","cldr-localenames-full":"37.0.0",colors:"^1.1.2","concat-files":"^0.1.1",d3:"~6.6.0","editor-layer-index":"github:osmlab/editor-layer-index#gh-pages",eslint:"^7.1.0",gaze:"^1.1.3",glob:"^7.1.0",happen:"^0.3.1","js-yaml":"^4.0.0","json-stringify-pretty-compact":"^3.0.0",mapillary_sprite_source:"^1.8.0","mapillary-js":"4.0.0",minimist:"^1.2.3",mocha:"^7.0.1","mocha-phantomjs-core":"^2.1.0","name-suggestion-index":"~6.0","node-fetch":"^2.6.1","npm-run-all":"^4.0.0","object-inspect":"1.10.3","osm-community-index":"~5.1.0","phantomjs-prebuilt":"~2.1.16",postcss:"^8.1.1","postcss-selector-prepend":"^0.5.0",rollup:"~2.52.8","rollup-plugin-includepaths":"~0.2.3","rollup-plugin-progress":"^1.1.1","rollup-plugin-visualizer":"~4.2.0",shelljs:"^0.8.0",shx:"^0.3.0",sinon:"7.5.0","sinon-chai":"^3.3.0",smash:"0.0","static-server":"^2.2.1","svg-sprite":"1.5.1","uglify-js":"~3.13.0",vparse:"~1.1.0"};
20989 var engines = {node:">=10"};
20990 var browserslist = ["> 0.2%, last 6 major versions, Firefox ESR, IE 11, maintained node versions"];
20991 var packageJSON = {
20994 description: description,
20996 repository: repository,
20997 homepage: homepage,
20999 keywords: keywords,
21002 dependencies: dependencies,
21003 devDependencies: devDependencies,
21005 browserslist: browserslist
21008 var _mainFileFetcher = coreFileFetcher(); // singleton
21009 // coreFileFetcher asynchronously fetches data from JSON files
21012 function coreFileFetcher() {
21013 var ociVersion = packageJSON.devDependencies['osm-community-index'];
21014 var v = parseVersion(ociVersion);
21015 var vMinor = "".concat(v.major, ".").concat(v.minor);
21017 var _inflight = {};
21019 'address_formats': 'data/address_formats.min.json',
21020 'deprecated': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/deprecated.min.json',
21021 'discarded': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/discarded.min.json',
21022 'imagery': 'data/imagery.min.json',
21023 'intro_graph': 'data/intro_graph.min.json',
21024 'keepRight': 'data/keepRight.min.json',
21025 'languages': 'data/languages.min.json',
21026 'locales': 'locales/index.min.json',
21027 'oci_defaults': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/defaults.min.json"),
21028 'oci_features': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/featureCollection.min.json"),
21029 'oci_resources': "https://cdn.jsdelivr.net/npm/osm-community-index@".concat(vMinor, "/dist/resources.min.json"),
21030 'preset_categories': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_categories.min.json',
21031 'preset_defaults': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/preset_defaults.min.json',
21032 'preset_fields': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/fields.min.json',
21033 'preset_presets': 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/presets.min.json',
21034 'phone_formats': 'data/phone_formats.min.json',
21035 'qa_data': 'data/qa_data.min.json',
21036 'shortcuts': 'data/shortcuts.min.json',
21037 'territory_languages': 'data/territory_languages.min.json',
21038 'wmf_sitematrix': 'https://cdn.jsdelivr.net/npm/wmf-sitematrix@0.1/wikipedia.min.json'
21040 var _cachedData = {}; // expose the cache; useful for tests
21042 _this.cache = function () {
21043 return _cachedData;
21044 }; // Returns a Promise to fetch data
21045 // (resolved with the data if we have it already)
21048 _this.get = function (which) {
21049 if (_cachedData[which]) {
21050 return Promise.resolve(_cachedData[which]);
21053 var file = _fileMap[which];
21055 var url = file && _this.asset(file);
21058 return Promise.reject("Unknown data file for \"".concat(which, "\""));
21061 var prom = _inflight[url];
21064 _inflight[url] = prom = fetch(url).then(function (response) {
21065 // fetch in PhantomJS tests may return ok=false and status=0 even if it's okay
21066 if (!response.ok && response.status !== 0 || !response.json) {
21067 throw new Error(response.status + ' ' + response.statusText);
21070 if (response.status === 204 || response.status === 205) return; // No Content, Reset Content
21072 return response.json();
21073 }).then(function (result) {
21074 delete _inflight[url];
21077 throw new Error("No data loaded for \"".concat(which, "\""));
21080 _cachedData[which] = result;
21082 })["catch"](function (err) {
21083 delete _inflight[url];
21089 }; // Accessor for the file map
21092 _this.fileMap = function (val) {
21093 if (!arguments.length) return _fileMap;
21098 var _assetPath = '';
21100 _this.assetPath = function (val) {
21101 if (!arguments.length) return _assetPath;
21106 var _assetMap = {};
21108 _this.assetMap = function (val) {
21109 if (!arguments.length) return _assetMap;
21114 _this.asset = function (val) {
21115 if (/^http(s)?:\/\//i.test(val)) return val;
21116 var filename = _assetPath + val;
21117 return _assetMap[filename] || filename;
21123 var classof = classofRaw$1;
21125 // `thisNumberValue` abstract operation
21126 // https://tc39.es/ecma262/#sec-thisnumbervalue
21127 var thisNumberValue$2 = function (value) {
21128 if (typeof value != 'number' && classof(value) != 'Number') {
21129 throw TypeError('Incorrect invocation');
21134 var toInteger$1 = toInteger$b;
21135 var requireObjectCoercible$6 = requireObjectCoercible$e;
21137 // `String.prototype.repeat` method implementation
21138 // https://tc39.es/ecma262/#sec-string.prototype.repeat
21139 var stringRepeat = function repeat(count) {
21140 var str = String(requireObjectCoercible$6(this));
21142 var n = toInteger$1(count);
21143 if (n < 0 || n == Infinity) throw RangeError('Wrong number of repetitions');
21144 for (;n > 0; (n >>>= 1) && (str += str)) if (n & 1) result += str;
21149 var toInteger = toInteger$b;
21150 var thisNumberValue$1 = thisNumberValue$2;
21151 var repeat$2 = stringRepeat;
21152 var fails$7 = fails$N;
21154 var nativeToFixed = 1.0.toFixed;
21155 var floor = Math.floor;
21157 var pow = function (x, n, acc) {
21158 return n === 0 ? acc : n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc);
21161 var log = function (x) {
21164 while (x2 >= 4096) {
21174 var multiply = function (data, n, c) {
21177 while (++index < 6) {
21178 c2 += n * data[index];
21179 data[index] = c2 % 1e7;
21180 c2 = floor(c2 / 1e7);
21184 var divide = function (data, n) {
21187 while (--index >= 0) {
21189 data[index] = floor(c / n);
21194 var dataToString = function (data) {
21197 while (--index >= 0) {
21198 if (s !== '' || index === 0 || data[index] !== 0) {
21199 var t = String(data[index]);
21200 s = s === '' ? t : s + repeat$2.call('0', 7 - t.length) + t;
21205 var FORCED$4 = nativeToFixed && (
21206 0.00008.toFixed(3) !== '0.000' ||
21207 0.9.toFixed(0) !== '1' ||
21208 1.255.toFixed(2) !== '1.25' ||
21209 1000000000000000128.0.toFixed(0) !== '1000000000000000128'
21210 ) || !fails$7(function () {
21211 // V8 ~ Android 4.3-
21212 nativeToFixed.call({});
21215 // `Number.prototype.toFixed` method
21216 // https://tc39.es/ecma262/#sec-number.prototype.tofixed
21217 $$j({ target: 'Number', proto: true, forced: FORCED$4 }, {
21218 toFixed: function toFixed(fractionDigits) {
21219 var number = thisNumberValue$1(this);
21220 var fractDigits = toInteger(fractionDigits);
21221 var data = [0, 0, 0, 0, 0, 0];
21226 if (fractDigits < 0 || fractDigits > 20) throw RangeError('Incorrect fraction digits');
21227 // eslint-disable-next-line no-self-compare -- NaN check
21228 if (number != number) return 'NaN';
21229 if (number <= -1e21 || number >= 1e21) return String(number);
21234 if (number > 1e-21) {
21235 e = log(number * pow(2, 69, 1)) - 69;
21236 z = e < 0 ? number * pow(2, -e, 1) : number / pow(2, e, 1);
21237 z *= 0x10000000000000;
21240 multiply(data, 0, z);
21243 multiply(data, 1e7, 0);
21246 multiply(data, pow(10, j, 1), 0);
21249 divide(data, 1 << 23);
21252 divide(data, 1 << j);
21253 multiply(data, 1, 1);
21255 result = dataToString(data);
21257 multiply(data, 0, z);
21258 multiply(data, 1 << -e, 0);
21259 result = dataToString(data) + repeat$2.call('0', fractDigits);
21262 if (fractDigits > 0) {
21264 result = sign + (k <= fractDigits
21265 ? '0.' + repeat$2.call('0', fractDigits - k) + result
21266 : result.slice(0, k - fractDigits) + '.' + result.slice(k - fractDigits));
21268 result = sign + result;
21273 var global$1 = global$F;
21275 var globalIsFinite = global$1.isFinite;
21277 // `Number.isFinite` method
21278 // https://tc39.es/ecma262/#sec-number.isfinite
21279 // eslint-disable-next-line es/no-number-isfinite -- safe
21280 var numberIsFinite$1 = Number.isFinite || function isFinite(it) {
21281 return typeof it == 'number' && globalIsFinite(it);
21285 var numberIsFinite = numberIsFinite$1;
21287 // `Number.isFinite` method
21288 // https://tc39.es/ecma262/#sec-number.isfinite
21289 $$i({ target: 'Number', stat: true }, { isFinite: numberIsFinite });
21292 var toAbsoluteIndex = toAbsoluteIndex$8;
21294 var fromCharCode = String.fromCharCode;
21295 // eslint-disable-next-line es/no-string-fromcodepoint -- required for testing
21296 var $fromCodePoint = String.fromCodePoint;
21298 // length should be 1, old FF problem
21299 var INCORRECT_LENGTH = !!$fromCodePoint && $fromCodePoint.length != 1;
21301 // `String.fromCodePoint` method
21302 // https://tc39.es/ecma262/#sec-string.fromcodepoint
21303 $$h({ target: 'String', stat: true, forced: INCORRECT_LENGTH }, {
21304 // eslint-disable-next-line no-unused-vars -- required for `.length`
21305 fromCodePoint: function fromCodePoint(x) {
21307 var length = arguments.length;
21310 while (length > i) {
21311 code = +arguments[i++];
21312 if (toAbsoluteIndex(code, 0x10FFFF) !== code) throw RangeError(code + ' is not a valid code point');
21313 elements.push(code < 0x10000
21314 ? fromCharCode(code)
21315 : fromCharCode(((code -= 0x10000) >> 10) + 0xD800, code % 0x400 + 0xDC00)
21317 } return elements.join('');
21321 var fixRegExpWellKnownSymbolLogic = fixRegexpWellKnownSymbolLogic;
21322 var anObject = anObject$m;
21323 var requireObjectCoercible$5 = requireObjectCoercible$e;
21324 var sameValue = sameValue$1;
21325 var regExpExec = regexpExecAbstract;
21328 fixRegExpWellKnownSymbolLogic('search', function (SEARCH, nativeSearch, maybeCallNative) {
21330 // `String.prototype.search` method
21331 // https://tc39.es/ecma262/#sec-string.prototype.search
21332 function search(regexp) {
21333 var O = requireObjectCoercible$5(this);
21334 var searcher = regexp == undefined ? undefined : regexp[SEARCH];
21335 return searcher !== undefined ? searcher.call(regexp, O) : new RegExp(regexp)[SEARCH](String(O));
21337 // `RegExp.prototype[@@search]` method
21338 // https://tc39.es/ecma262/#sec-regexp.prototype-@@search
21339 function (string) {
21340 var res = maybeCallNative(nativeSearch, this, string);
21341 if (res.done) return res.value;
21343 var rx = anObject(this);
21344 var S = String(string);
21346 var previousLastIndex = rx.lastIndex;
21347 if (!sameValue(previousLastIndex, 0)) rx.lastIndex = 0;
21348 var result = regExpExec(rx, S);
21349 if (!sameValue(rx.lastIndex, previousLastIndex)) rx.lastIndex = previousLastIndex;
21350 return result === null ? -1 : result.index;
21355 var rbush$2 = {exports: {}};
21357 var quickselect$2 = {exports: {}};
21359 (function (module, exports) {
21360 (function (global, factory) {
21361 module.exports = factory() ;
21362 })(commonjsGlobal, function () {
21364 function quickselect(arr, k, left, right, compare) {
21365 quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
21368 function quickselectStep(arr, k, left, right, compare) {
21369 while (right > left) {
21370 if (right - left > 600) {
21371 var n = right - left + 1;
21372 var m = k - left + 1;
21373 var z = Math.log(n);
21374 var s = 0.5 * Math.exp(2 * z / 3);
21375 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
21376 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
21377 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
21378 quickselectStep(arr, k, newLeft, newRight, compare);
21384 swap(arr, left, k);
21385 if (compare(arr[right], t) > 0) swap(arr, left, right);
21392 while (compare(arr[i], t) < 0) {
21396 while (compare(arr[j], t) > 0) {
21401 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
21403 swap(arr, j, right);
21405 if (j <= k) left = j + 1;
21406 if (k <= j) right = j - 1;
21410 function swap(arr, i, j) {
21416 function defaultCompare(a, b) {
21417 return a < b ? -1 : a > b ? 1 : 0;
21420 return quickselect;
21424 rbush$2.exports = rbush$1;
21426 rbush$2.exports["default"] = rbush$1;
21428 var quickselect$1 = quickselect$2.exports;
21430 function rbush$1(maxEntries, format) {
21431 if (!(this instanceof rbush$1)) return new rbush$1(maxEntries, format); // max entries in a node is 9 by default; min node fill is 40% for best performance
21433 this._maxEntries = Math.max(4, maxEntries || 9);
21434 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
21437 this._initFormat(format);
21443 rbush$1.prototype = {
21444 all: function all() {
21445 return this._all(this.data, []);
21447 search: function search(bbox) {
21448 var node = this.data,
21450 toBBox = this.toBBox;
21451 if (!intersects$1(bbox, node)) return result;
21452 var nodesToSearch = [],
21459 for (i = 0, len = node.children.length; i < len; i++) {
21460 child = node.children[i];
21461 childBBox = node.leaf ? toBBox(child) : child;
21463 if (intersects$1(bbox, childBBox)) {
21464 if (node.leaf) result.push(child);else if (contains$1(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
21468 node = nodesToSearch.pop();
21473 collides: function collides(bbox) {
21474 var node = this.data,
21475 toBBox = this.toBBox;
21476 if (!intersects$1(bbox, node)) return false;
21477 var nodesToSearch = [],
21484 for (i = 0, len = node.children.length; i < len; i++) {
21485 child = node.children[i];
21486 childBBox = node.leaf ? toBBox(child) : child;
21488 if (intersects$1(bbox, childBBox)) {
21489 if (node.leaf || contains$1(bbox, childBBox)) return true;
21490 nodesToSearch.push(child);
21494 node = nodesToSearch.pop();
21499 load: function load(data) {
21500 if (!(data && data.length)) return this;
21502 if (data.length < this._minEntries) {
21503 for (var i = 0, len = data.length; i < len; i++) {
21504 this.insert(data[i]);
21508 } // recursively build the tree with the given data from scratch using OMT algorithm
21511 var node = this._build(data.slice(), 0, data.length - 1, 0);
21513 if (!this.data.children.length) {
21514 // save as is if tree is empty
21516 } else if (this.data.height === node.height) {
21517 // split root if trees have the same height
21518 this._splitRoot(this.data, node);
21520 if (this.data.height < node.height) {
21521 // swap trees if inserted one is bigger
21522 var tmpNode = this.data;
21525 } // insert the small tree into the large tree at appropriate level
21528 this._insert(node, this.data.height - node.height - 1, true);
21533 insert: function insert(item) {
21534 if (item) this._insert(item, this.data.height - 1);
21537 clear: function clear() {
21538 this.data = createNode$1([]);
21541 remove: function remove(item, equalsFn) {
21542 if (!item) return this;
21543 var node = this.data,
21544 bbox = this.toBBox(item),
21550 goingUp; // depth-first iterative tree traversal
21552 while (node || path.length) {
21556 parent = path[path.length - 1];
21562 // check current node
21563 index = findItem$1(item, node.children, equalsFn);
21565 if (index !== -1) {
21566 // item found, remove the item and condense tree upwards
21567 node.children.splice(index, 1);
21570 this._condense(path);
21576 if (!goingUp && !node.leaf && contains$1(node, bbox)) {
21582 node = node.children[0];
21583 } else if (parent) {
21586 node = parent.children[i];
21588 } else node = null; // nothing found
21594 toBBox: function toBBox(item) {
21597 compareMinX: compareNodeMinX$1,
21598 compareMinY: compareNodeMinY$1,
21599 toJSON: function toJSON() {
21602 fromJSON: function fromJSON(data) {
21606 _all: function _all(node, result) {
21607 var nodesToSearch = [];
21610 if (node.leaf) result.push.apply(result, node.children);else nodesToSearch.push.apply(nodesToSearch, node.children);
21611 node = nodesToSearch.pop();
21616 _build: function _build(items, left, right, height) {
21617 var N = right - left + 1,
21618 M = this._maxEntries,
21622 // reached leaf level; return leaf
21623 node = createNode$1(items.slice(left, right + 1));
21624 calcBBox$1(node, this.toBBox);
21629 // target height of the bulk-loaded tree
21630 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
21632 M = Math.ceil(N / Math.pow(M, height - 1));
21635 node = createNode$1([]);
21637 node.height = height; // split the items into M mostly square tiles
21639 var N2 = Math.ceil(N / M),
21640 N1 = N2 * Math.ceil(Math.sqrt(M)),
21645 multiSelect$1(items, left, right, N1, this.compareMinX);
21647 for (i = left; i <= right; i += N1) {
21648 right2 = Math.min(i + N1 - 1, right);
21649 multiSelect$1(items, i, right2, N2, this.compareMinY);
21651 for (j = i; j <= right2; j += N2) {
21652 right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
21654 node.children.push(this._build(items, j, right3, height - 1));
21658 calcBBox$1(node, this.toBBox);
21661 _chooseSubtree: function _chooseSubtree(bbox, node, level, path) {
21662 var i, len, child, targetNode, area, enlargement, minArea, minEnlargement;
21666 if (node.leaf || path.length - 1 === level) break;
21667 minArea = minEnlargement = Infinity;
21669 for (i = 0, len = node.children.length; i < len; i++) {
21670 child = node.children[i];
21671 area = bboxArea$1(child);
21672 enlargement = enlargedArea$1(bbox, child) - area; // choose entry with the least area enlargement
21674 if (enlargement < minEnlargement) {
21675 minEnlargement = enlargement;
21676 minArea = area < minArea ? area : minArea;
21677 targetNode = child;
21678 } else if (enlargement === minEnlargement) {
21679 // otherwise choose one with the smallest area
21680 if (area < minArea) {
21682 targetNode = child;
21687 node = targetNode || node.children[0];
21692 _insert: function _insert(item, level, isNode) {
21693 var toBBox = this.toBBox,
21694 bbox = isNode ? item : toBBox(item),
21695 insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
21697 var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
21700 node.children.push(item);
21701 extend$2(node, bbox); // split on node overflow; propagate upwards if necessary
21703 while (level >= 0) {
21704 if (insertPath[level].children.length > this._maxEntries) {
21705 this._split(insertPath, level);
21709 } // adjust bboxes along the insertion path
21712 this._adjustParentBBoxes(bbox, insertPath, level);
21714 // split overflowed node into two
21715 _split: function _split(insertPath, level) {
21716 var node = insertPath[level],
21717 M = node.children.length,
21718 m = this._minEntries;
21720 this._chooseSplitAxis(node, m, M);
21722 var splitIndex = this._chooseSplitIndex(node, m, M);
21724 var newNode = createNode$1(node.children.splice(splitIndex, node.children.length - splitIndex));
21725 newNode.height = node.height;
21726 newNode.leaf = node.leaf;
21727 calcBBox$1(node, this.toBBox);
21728 calcBBox$1(newNode, this.toBBox);
21729 if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
21731 _splitRoot: function _splitRoot(node, newNode) {
21733 this.data = createNode$1([node, newNode]);
21734 this.data.height = node.height + 1;
21735 this.data.leaf = false;
21736 calcBBox$1(this.data, this.toBBox);
21738 _chooseSplitIndex: function _chooseSplitIndex(node, m, M) {
21739 var i, bbox1, bbox2, overlap, area, minOverlap, minArea, index;
21740 minOverlap = minArea = Infinity;
21742 for (i = m; i <= M - m; i++) {
21743 bbox1 = distBBox$1(node, 0, i, this.toBBox);
21744 bbox2 = distBBox$1(node, i, M, this.toBBox);
21745 overlap = intersectionArea$1(bbox1, bbox2);
21746 area = bboxArea$1(bbox1) + bboxArea$1(bbox2); // choose distribution with minimum overlap
21748 if (overlap < minOverlap) {
21749 minOverlap = overlap;
21751 minArea = area < minArea ? area : minArea;
21752 } else if (overlap === minOverlap) {
21753 // otherwise choose distribution with minimum area
21754 if (area < minArea) {
21763 // sorts node children by the best axis for split
21764 _chooseSplitAxis: function _chooseSplitAxis(node, m, M) {
21765 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX$1,
21766 compareMinY = node.leaf ? this.compareMinY : compareNodeMinY$1,
21767 xMargin = this._allDistMargin(node, m, M, compareMinX),
21768 yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
21769 // otherwise it's already sorted by minY
21772 if (xMargin < yMargin) node.children.sort(compareMinX);
21774 // total margin of all possible split distributions where each node is at least m full
21775 _allDistMargin: function _allDistMargin(node, m, M, compare) {
21776 node.children.sort(compare);
21777 var toBBox = this.toBBox,
21778 leftBBox = distBBox$1(node, 0, m, toBBox),
21779 rightBBox = distBBox$1(node, M - m, M, toBBox),
21780 margin = bboxMargin$1(leftBBox) + bboxMargin$1(rightBBox),
21784 for (i = m; i < M - m; i++) {
21785 child = node.children[i];
21786 extend$2(leftBBox, node.leaf ? toBBox(child) : child);
21787 margin += bboxMargin$1(leftBBox);
21790 for (i = M - m - 1; i >= m; i--) {
21791 child = node.children[i];
21792 extend$2(rightBBox, node.leaf ? toBBox(child) : child);
21793 margin += bboxMargin$1(rightBBox);
21798 _adjustParentBBoxes: function _adjustParentBBoxes(bbox, path, level) {
21799 // adjust bboxes along the given tree path
21800 for (var i = level; i >= 0; i--) {
21801 extend$2(path[i], bbox);
21804 _condense: function _condense(path) {
21805 // go through the path, removing empty nodes and updating bboxes
21806 for (var i = path.length - 1, siblings; i >= 0; i--) {
21807 if (path[i].children.length === 0) {
21809 siblings = path[i - 1].children;
21810 siblings.splice(siblings.indexOf(path[i]), 1);
21811 } else this.clear();
21812 } else calcBBox$1(path[i], this.toBBox);
21815 _initFormat: function _initFormat(format) {
21816 // data format (minX, minY, maxX, maxY accessors)
21817 // uses eval-type function compilation instead of just accepting a toBBox function
21818 // because the algorithms are very sensitive to sorting functions performance,
21819 // so they should be dead simple and without inner calls
21820 var compareArr = ['return a', ' - b', ';'];
21821 this.compareMinX = new Function('a', 'b', compareArr.join(format[0]));
21822 this.compareMinY = new Function('a', 'b', compareArr.join(format[1]));
21823 this.toBBox = new Function('a', 'return {minX: a' + format[0] + ', minY: a' + format[1] + ', maxX: a' + format[2] + ', maxY: a' + format[3] + '};');
21827 function findItem$1(item, items, equalsFn) {
21828 if (!equalsFn) return items.indexOf(item);
21830 for (var i = 0; i < items.length; i++) {
21831 if (equalsFn(item, items[i])) return i;
21835 } // calculate node's bbox from bboxes of its children
21838 function calcBBox$1(node, toBBox) {
21839 distBBox$1(node, 0, node.children.length, toBBox, node);
21840 } // min bounding rectangle of node children from k to p-1
21843 function distBBox$1(node, k, p, toBBox, destNode) {
21844 if (!destNode) destNode = createNode$1(null);
21845 destNode.minX = Infinity;
21846 destNode.minY = Infinity;
21847 destNode.maxX = -Infinity;
21848 destNode.maxY = -Infinity;
21850 for (var i = k, child; i < p; i++) {
21851 child = node.children[i];
21852 extend$2(destNode, node.leaf ? toBBox(child) : child);
21858 function extend$2(a, b) {
21859 a.minX = Math.min(a.minX, b.minX);
21860 a.minY = Math.min(a.minY, b.minY);
21861 a.maxX = Math.max(a.maxX, b.maxX);
21862 a.maxY = Math.max(a.maxY, b.maxY);
21866 function compareNodeMinX$1(a, b) {
21867 return a.minX - b.minX;
21870 function compareNodeMinY$1(a, b) {
21871 return a.minY - b.minY;
21874 function bboxArea$1(a) {
21875 return (a.maxX - a.minX) * (a.maxY - a.minY);
21878 function bboxMargin$1(a) {
21879 return a.maxX - a.minX + (a.maxY - a.minY);
21882 function enlargedArea$1(a, b) {
21883 return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
21886 function intersectionArea$1(a, b) {
21887 var minX = Math.max(a.minX, b.minX),
21888 minY = Math.max(a.minY, b.minY),
21889 maxX = Math.min(a.maxX, b.maxX),
21890 maxY = Math.min(a.maxY, b.maxY);
21891 return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
21894 function contains$1(a, b) {
21895 return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
21898 function intersects$1(a, b) {
21899 return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
21902 function createNode$1(children) {
21904 children: children,
21912 } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
21913 // combines selection algorithm with binary divide & conquer approach
21916 function multiSelect$1(arr, left, right, n, compare) {
21917 var stack = [left, right],
21920 while (stack.length) {
21921 right = stack.pop();
21922 left = stack.pop();
21923 if (right - left <= n) continue;
21924 mid = left + Math.ceil((right - left) / n / 2) * n;
21925 quickselect$1(arr, mid, left, right, compare);
21926 stack.push(left, mid, mid, right);
21930 var lineclip_1 = lineclip$2;
21931 lineclip$2.polyline = lineclip$2;
21932 lineclip$2.polygon = polygonclip$1; // Cohen-Sutherland line clippign algorithm, adapted to efficiently
21933 // handle polylines rather than just segments
21935 function lineclip$2(points, bbox, result) {
21936 var len = points.length,
21937 codeA = bitCode$1(points[0], bbox),
21944 if (!result) result = [];
21946 for (i = 1; i < len; i++) {
21949 codeB = lastCode = bitCode$1(b, bbox);
21952 if (!(codeA | codeB)) {
21956 if (codeB !== lastCode) {
21957 // segment went outside
21961 // start a new line
21965 } else if (i === len - 1) {
21970 } else if (codeA & codeB) {
21973 } else if (codeA) {
21974 // a outside, intersect with clip edge
21975 a = intersect$1(a, b, codeA, bbox);
21976 codeA = bitCode$1(a, bbox);
21979 b = intersect$1(a, b, codeB, bbox);
21980 codeB = bitCode$1(b, bbox);
21987 if (part.length) result.push(part);
21989 } // Sutherland-Hodgeman polygon clipping algorithm
21992 function polygonclip$1(points, bbox) {
21993 var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
21995 for (edge = 1; edge <= 8; edge *= 2) {
21997 prev = points[points.length - 1];
21998 prevInside = !(bitCode$1(prev, bbox) & edge);
22000 for (i = 0; i < points.length; i++) {
22002 inside = !(bitCode$1(p, bbox) & edge); // if segment goes through the clip window, add an intersection
22004 if (inside !== prevInside) result.push(intersect$1(prev, p, edge, bbox));
22005 if (inside) result.push(p); // add a point if it's inside
22008 prevInside = inside;
22012 if (!points.length) break;
22016 } // intersect a segment against one of the 4 lines that make up the bbox
22019 function intersect$1(a, b, edge, bbox) {
22020 return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] : // top
22021 edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] : // bottom
22022 edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] : // right
22023 edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] : // left
22025 } // bit code reflects the point position relative to the bbox:
22027 // top 1001 1000 1010
22028 // mid 0001 0000 0010
22029 // bottom 0101 0100 0110
22032 function bitCode$1(p, bbox) {
22034 if (p[0] < bbox[0]) code |= 1; // left
22035 else if (p[0] > bbox[2]) code |= 2; // right
22037 if (p[1] < bbox[1]) code |= 4; // bottom
22038 else if (p[1] > bbox[3]) code |= 8; // top
22043 var rbush = rbush$2.exports;
22044 var lineclip$1 = lineclip_1;
22045 var whichPolygon_1 = whichPolygon;
22047 function whichPolygon(data) {
22050 for (var i = 0; i < data.features.length; i++) {
22051 var feature = data.features[i];
22052 var coords = feature.geometry.coordinates;
22054 if (feature.geometry.type === 'Polygon') {
22055 bboxes.push(treeItem(coords, feature.properties));
22056 } else if (feature.geometry.type === 'MultiPolygon') {
22057 for (var j = 0; j < coords.length; j++) {
22058 bboxes.push(treeItem(coords[j], feature.properties));
22063 var tree = rbush().load(bboxes);
22065 function query(p, multi) {
22067 result = tree.search({
22074 for (var i = 0; i < result.length; i++) {
22075 if (insidePolygon(result[i].coords, p)) {
22076 if (multi) output.push(result[i].props);else return result[i].props;
22080 return multi && output.length ? output : null;
22085 query.bbox = function queryBBox(bbox) {
22087 var result = tree.search({
22094 for (var i = 0; i < result.length; i++) {
22095 if (polygonIntersectsBBox(result[i].coords, bbox)) {
22096 output.push(result[i].props);
22106 function polygonIntersectsBBox(polygon, bbox) {
22107 var bboxCenter = [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2];
22108 if (insidePolygon(polygon, bboxCenter)) return true;
22110 for (var i = 0; i < polygon.length; i++) {
22111 if (lineclip$1(polygon[i], bbox).length > 0) return true;
22115 } // ray casting algorithm for detecting if point is in polygon
22118 function insidePolygon(rings, p) {
22119 var inside = false;
22121 for (var i = 0, len = rings.length; i < len; i++) {
22122 var ring = rings[i];
22124 for (var j = 0, len2 = ring.length, k = len2 - 1; j < len2; k = j++) {
22125 if (rayIntersect(p, ring[j], ring[k])) inside = !inside;
22132 function rayIntersect(p, p1, p2) {
22133 return p1[1] > p[1] !== p2[1] > p[1] && p[0] < (p2[0] - p1[0]) * (p[1] - p1[1]) / (p2[1] - p1[1]) + p1[0];
22136 function treeItem(coords, props) {
22146 for (var i = 0; i < coords[0].length; i++) {
22147 var p = coords[0][i];
22148 item.minX = Math.min(item.minX, p[0]);
22149 item.minY = Math.min(item.minY, p[1]);
22150 item.maxX = Math.max(item.maxX, p[0]);
22151 item.maxY = Math.max(item.maxY, p[1]);
22157 var type = "FeatureCollection";
22163 aliases: ["GB-ENG"],
22165 groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22167 roadSpeedUnit: "mph",
22168 roadHeightUnit: "ft",
22169 callingCodes: ["44"]
22172 type: "MultiPolygon",
22173 coordinates: [[[[-6.03913, 51.13217], [-7.74976, 48.64773], [1.17405, 50.74239], [2.18458, 51.52087], [2.56575, 51.85301], [0.792, 57.56437], [-2.30613, 55.62698], [-2.17058, 55.45916], [-2.6095, 55.28488], [-2.63532, 55.19452], [-3.02906, 55.04606], [-3.09361, 54.94924], [-3.38407, 54.94278], [-4.1819, 54.57861], [-3.5082, 53.54318], [-3.08228, 53.25526], [-3.03675, 53.25092], [-2.92329, 53.19383], [-2.92022, 53.17685], [-2.98598, 53.15589], [-2.90649, 53.10964], [-2.87469, 53.12337], [-2.89131, 53.09374], [-2.83133, 52.99184], [-2.7251, 52.98389], [-2.72221, 52.92969], [-2.80549, 52.89428], [-2.85897, 52.94487], [-2.92401, 52.93836], [-2.97243, 52.9651], [-3.13576, 52.895], [-3.15744, 52.84947], [-3.16105, 52.79599], [-3.08734, 52.77504], [-3.01001, 52.76636], [-2.95581, 52.71794], [-3.01724, 52.72083], [-3.04398, 52.65435], [-3.13648, 52.58208], [-3.12926, 52.5286], [-3.09746, 52.53077], [-3.08662, 52.54811], [-3.00929, 52.57774], [-2.99701, 52.551], [-3.03603, 52.49969], [-3.13359, 52.49174], [-3.22971, 52.45344], [-3.22754, 52.42526], [-3.04687, 52.34504], [-2.95364, 52.3501], [-2.99701, 52.323], [-3.00785, 52.2753], [-3.09289, 52.20546], [-3.12638, 52.08114], [-2.97111, 51.90456], [-2.8818, 51.93196], [-2.78742, 51.88833], [-2.74277, 51.84367], [-2.66234, 51.83555], [-2.66336, 51.59504], [-3.20563, 51.31615], [-6.03913, 51.13217]]]]
22179 nameEn: "Scotland",
22180 aliases: ["GB-SCT"],
22182 groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22184 roadSpeedUnit: "mph",
22185 roadHeightUnit: "ft",
22186 callingCodes: ["44"]
22189 type: "MultiPolygon",
22190 coordinates: [[[[0.792, 57.56437], [-0.3751, 61.32236], [-14.78497, 57.60709], [-6.82333, 55.83103], [-4.69044, 54.3629], [-3.38407, 54.94278], [-3.09361, 54.94924], [-3.02906, 55.04606], [-2.63532, 55.19452], [-2.6095, 55.28488], [-2.17058, 55.45916], [-2.30613, 55.62698], [0.792, 57.56437]]]]
22197 aliases: ["GB-WLS"],
22199 groups: ["Q23666", "Q3336843", "154", "150", "UN"],
22201 roadSpeedUnit: "mph",
22202 roadHeightUnit: "ft",
22203 callingCodes: ["44"]
22206 type: "MultiPolygon",
22207 coordinates: [[[[-3.5082, 53.54318], [-5.37267, 53.63269], [-6.03913, 51.13217], [-3.20563, 51.31615], [-2.66336, 51.59504], [-2.66234, 51.83555], [-2.74277, 51.84367], [-2.78742, 51.88833], [-2.8818, 51.93196], [-2.97111, 51.90456], [-3.12638, 52.08114], [-3.09289, 52.20546], [-3.00785, 52.2753], [-2.99701, 52.323], [-2.95364, 52.3501], [-3.04687, 52.34504], [-3.22754, 52.42526], [-3.22971, 52.45344], [-3.13359, 52.49174], [-3.03603, 52.49969], [-2.99701, 52.551], [-3.00929, 52.57774], [-3.08662, 52.54811], [-3.09746, 52.53077], [-3.12926, 52.5286], [-3.13648, 52.58208], [-3.04398, 52.65435], [-3.01724, 52.72083], [-2.95581, 52.71794], [-3.01001, 52.76636], [-3.08734, 52.77504], [-3.16105, 52.79599], [-3.15744, 52.84947], [-3.13576, 52.895], [-2.97243, 52.9651], [-2.92401, 52.93836], [-2.85897, 52.94487], [-2.80549, 52.89428], [-2.72221, 52.92969], [-2.7251, 52.98389], [-2.83133, 52.99184], [-2.89131, 53.09374], [-2.87469, 53.12337], [-2.90649, 53.10964], [-2.98598, 53.15589], [-2.92022, 53.17685], [-2.92329, 53.19383], [-3.03675, 53.25092], [-3.08228, 53.25526], [-3.5082, 53.54318]]]]
22213 nameEn: "Northern Ireland",
22214 aliases: ["GB-NIR"],
22216 groups: ["Q22890", "Q3336843", "154", "150", "UN"],
22218 roadSpeedUnit: "mph",
22219 roadHeightUnit: "ft",
22220 callingCodes: ["44"]
22223 type: "MultiPolygon",
22224 coordinates: [[[[-6.34755, 55.49206], [-7.2471, 55.06933], [-7.34464, 55.04688], [-7.4033, 55.00391], [-7.40004, 54.94498], [-7.44404, 54.9403], [-7.4473, 54.87003], [-7.47626, 54.83084], [-7.54508, 54.79401], [-7.54671, 54.74606], [-7.64449, 54.75265], [-7.75041, 54.7103], [-7.83352, 54.73854], [-7.93293, 54.66603], [-7.70315, 54.62077], [-7.8596, 54.53671], [-7.99812, 54.54427], [-8.04538, 54.48941], [-8.179, 54.46763], [-8.04555, 54.36292], [-7.87101, 54.29299], [-7.8596, 54.21779], [-7.81397, 54.20159], [-7.69501, 54.20731], [-7.55812, 54.12239], [-7.4799, 54.12239], [-7.44567, 54.1539], [-7.32834, 54.11475], [-7.30553, 54.11869], [-7.34005, 54.14698], [-7.29157, 54.17191], [-7.28017, 54.16714], [-7.29687, 54.1354], [-7.29493, 54.12013], [-7.26316, 54.13863], [-7.25012, 54.20063], [-7.14908, 54.22732], [-7.19145, 54.31296], [-7.02034, 54.4212], [-6.87775, 54.34682], [-6.85179, 54.29176], [-6.81583, 54.22791], [-6.74575, 54.18788], [-6.70175, 54.20218], [-6.6382, 54.17071], [-6.66264, 54.0666], [-6.62842, 54.03503], [-6.47849, 54.06947], [-6.36605, 54.07234], [-6.36279, 54.11248], [-6.32694, 54.09337], [-6.29003, 54.11278], [-6.26218, 54.09785], [-5.83481, 53.87749], [-4.69044, 54.3629], [-6.34755, 55.49206]]]]
22232 groups: ["EU", "154", "150", "UN"],
22233 callingCodes: ["45"]
22236 type: "MultiPolygon",
22237 coordinates: [[[[12.16597, 56.60205], [10.40861, 58.38489], [7.28637, 57.35913], [8.02459, 55.09613], [8.45719, 55.06747], [8.55769, 54.91837], [8.63979, 54.91069], [8.76387, 54.8948], [8.81178, 54.90518], [8.92795, 54.90452], [9.04629, 54.87249], [9.14275, 54.87421], [9.20571, 54.85841], [9.24631, 54.84726], [9.23445, 54.83432], [9.2474, 54.8112], [9.32771, 54.80602], [9.33849, 54.80233], [9.36496, 54.81749], [9.38532, 54.83968], [9.41213, 54.84254], [9.43155, 54.82586], [9.4659, 54.83131], [9.58937, 54.88785], [9.62734, 54.88057], [9.61187, 54.85548], [9.73563, 54.8247], [9.89314, 54.84171], [10.16755, 54.73883], [10.31111, 54.65968], [11.00303, 54.63689], [11.90309, 54.38543], [12.85844, 54.82438], [13.93395, 54.84044], [15.36991, 54.73263], [15.79951, 55.54655], [14.89259, 55.5623], [14.28399, 55.1553], [12.84405, 55.13257], [12.60345, 55.42675], [12.88472, 55.63369], [12.6372, 55.91371], [12.65312, 56.04345], [12.07466, 56.29488], [12.16597, 56.60205]]]]
22243 nameEn: "Netherlands",
22245 groups: ["EU", "155", "150", "UN"],
22246 callingCodes: ["31"]
22249 type: "MultiPolygon",
22250 coordinates: [[[[5.45168, 54.20039], [2.56575, 51.85301], [3.36263, 51.37112], [3.38696, 51.33436], [3.35847, 51.31572], [3.38289, 51.27331], [3.41704, 51.25933], [3.43488, 51.24135], [3.52698, 51.2458], [3.51502, 51.28697], [3.58939, 51.30064], [3.78999, 51.25766], [3.78783, 51.2151], [3.90125, 51.20371], [3.97889, 51.22537], [4.01957, 51.24504], [4.05165, 51.24171], [4.16721, 51.29348], [4.24024, 51.35371], [4.21923, 51.37443], [4.33265, 51.37687], [4.34086, 51.35738], [4.39292, 51.35547], [4.43777, 51.36989], [4.38064, 51.41965], [4.39747, 51.43316], [4.38122, 51.44905], [4.47736, 51.4778], [4.5388, 51.48184], [4.54675, 51.47265], [4.52846, 51.45002], [4.53521, 51.4243], [4.57489, 51.4324], [4.65442, 51.42352], [4.72935, 51.48424], [4.74578, 51.48937], [4.77321, 51.50529], [4.78803, 51.50284], [4.84139, 51.4799], [4.82409, 51.44736], [4.82946, 51.4213], [4.78314, 51.43319], [4.76577, 51.43046], [4.77229, 51.41337], [4.78941, 51.41102], [4.84988, 51.41502], [4.90016, 51.41404], [4.92152, 51.39487], [5.00393, 51.44406], [5.0106, 51.47167], [5.03281, 51.48679], [5.04774, 51.47022], [5.07891, 51.4715], [5.10456, 51.43163], [5.07102, 51.39469], [5.13105, 51.34791], [5.13377, 51.31592], [5.16222, 51.31035], [5.2002, 51.32243], [5.24244, 51.30495], [5.22542, 51.26888], [5.23814, 51.26064], [5.26461, 51.26693], [5.29716, 51.26104], [5.33886, 51.26314], [5.347, 51.27502], [5.41672, 51.26248], [5.4407, 51.28169], [5.46519, 51.2849], [5.48476, 51.30053], [5.515, 51.29462], [5.5569, 51.26544], [5.5603, 51.22249], [5.65145, 51.19788], [5.65528, 51.18736], [5.70344, 51.1829], [5.74617, 51.18928], [5.77735, 51.17845], [5.77697, 51.1522], [5.82564, 51.16753], [5.85508, 51.14445], [5.80798, 51.11661], [5.8109, 51.10861], [5.83226, 51.10585], [5.82921, 51.09328], [5.79903, 51.09371], [5.79835, 51.05834], [5.77258, 51.06196], [5.75961, 51.03113], [5.77688, 51.02483], [5.76242, 50.99703], [5.71864, 50.96092], [5.72875, 50.95428], [5.74752, 50.96202], [5.75927, 50.95601], [5.74644, 50.94723], [5.72545, 50.92312], [5.72644, 50.91167], [5.71626, 50.90796], [5.69858, 50.91046], [5.67886, 50.88142], [5.64504, 50.87107], [5.64009, 50.84742], [5.65259, 50.82309], [5.70118, 50.80764], [5.68995, 50.79641], [5.70107, 50.7827], [5.68091, 50.75804], [5.69469, 50.75529], [5.72216, 50.76398], [5.73904, 50.75674], [5.74356, 50.7691], [5.76533, 50.78159], [5.77513, 50.78308], [5.80673, 50.7558], [5.84548, 50.76542], [5.84888, 50.75448], [5.88734, 50.77092], [5.89129, 50.75125], [5.89132, 50.75124], [5.95942, 50.7622], [5.97545, 50.75441], [6.01976, 50.75398], [6.02624, 50.77453], [5.97497, 50.79992], [5.98404, 50.80988], [6.00462, 50.80065], [6.02328, 50.81694], [6.01921, 50.84435], [6.05623, 50.8572], [6.05702, 50.85179], [6.07431, 50.84674], [6.07693, 50.86025], [6.08805, 50.87223], [6.07486, 50.89307], [6.09297, 50.92066], [6.01615, 50.93367], [6.02697, 50.98303], [5.95282, 50.98728], [5.90296, 50.97356], [5.90493, 51.00198], [5.87849, 51.01969], [5.86735, 51.05182], [5.9134, 51.06736], [5.9541, 51.03496], [5.98292, 51.07469], [6.16706, 51.15677], [6.17384, 51.19589], [6.07889, 51.17038], [6.07889, 51.24432], [6.16977, 51.33169], [6.22674, 51.36135], [6.22641, 51.39948], [6.20654, 51.40049], [6.21724, 51.48568], [6.18017, 51.54096], [6.09055, 51.60564], [6.11759, 51.65609], [6.02767, 51.6742], [6.04091, 51.71821], [5.95003, 51.7493], [5.98665, 51.76944], [5.94568, 51.82786], [5.99848, 51.83195], [6.06705, 51.86136], [6.10337, 51.84829], [6.16902, 51.84094], [6.11551, 51.89769], [6.15349, 51.90439], [6.21443, 51.86801], [6.29872, 51.86801], [6.30593, 51.84998], [6.40704, 51.82771], [6.38815, 51.87257], [6.47179, 51.85395], [6.50231, 51.86313], [6.58556, 51.89386], [6.68386, 51.91861], [6.72319, 51.89518], [6.82357, 51.96711], [6.83035, 51.9905], [6.68128, 52.05052], [6.76117, 52.11895], [6.83984, 52.11728], [6.97189, 52.20329], [6.9897, 52.2271], [7.03729, 52.22695], [7.06365, 52.23789], [7.02703, 52.27941], [7.07044, 52.37805], [7.03417, 52.40237], [6.99041, 52.47235], [6.94293, 52.43597], [6.69507, 52.488], [6.71641, 52.62905], [6.77307, 52.65375], [7.04557, 52.63318], [7.07253, 52.81083], [7.21694, 53.00742], [7.17898, 53.13817], [7.22681, 53.18165], [7.21679, 53.20058], [7.19052, 53.31866], [7.00198, 53.32672], [6.91025, 53.44221], [5.45168, 54.20039]], [[4.93295, 51.44945], [4.95244, 51.45207], [4.9524, 51.45014], [4.93909, 51.44632], [4.93295, 51.44945]], [[4.91493, 51.4353], [4.91935, 51.43634], [4.92227, 51.44252], [4.91811, 51.44621], [4.92287, 51.44741], [4.92811, 51.4437], [4.92566, 51.44273], [4.92815, 51.43856], [4.92879, 51.44161], [4.93544, 51.44634], [4.94025, 51.44193], [4.93416, 51.44185], [4.93471, 51.43861], [4.94265, 51.44003], [4.93986, 51.43064], [4.92952, 51.42984], [4.92652, 51.43329], [4.91493, 51.4353]]]]
22257 aliases: ["US-HI"],
22259 groups: ["Q35657", "061", "009", "UN"],
22260 roadSpeedUnit: "mph",
22261 roadHeightUnit: "ft",
22262 callingCodes: ["1"]
22265 type: "MultiPolygon",
22266 coordinates: [[[[-177.8563, 29.18961], [-179.49839, 27.86265], [-151.6784, 9.55515], [-154.05867, 45.51124], [-177.5224, 27.7635], [-177.8563, 29.18961]]]]
22273 aliases: ["US-AK"],
22275 groups: ["Q35657", "021", "003", "019", "UN"],
22276 roadSpeedUnit: "mph",
22277 roadHeightUnit: "ft",
22278 callingCodes: ["1"]
22281 type: "MultiPolygon",
22282 coordinates: [[[[169.34848, 52.47228], [180, 51.0171], [179.84401, 55.10087], [169.34848, 52.47228]]], [[[-168.95635, 65.98512], [-169.03888, 65.48473], [-172.76104, 63.77445], [-179.55295, 57.62081], [-179.55295, 50.81807], [-133.92876, 54.62289], [-130.61931, 54.70835], [-130.64499, 54.76912], [-130.44184, 54.85377], [-130.27203, 54.97174], [-130.18765, 55.07744], [-130.08035, 55.21556], [-129.97513, 55.28029], [-130.15373, 55.74895], [-130.00857, 55.91344], [-130.00093, 56.00325], [-130.10173, 56.12178], [-130.33965, 56.10849], [-130.77769, 56.36185], [-131.8271, 56.62247], [-133.38523, 58.42773], [-133.84645, 58.73543], [-134.27175, 58.8634], [-134.48059, 59.13231], [-134.55699, 59.1297], [-134.7047, 59.2458], [-135.00267, 59.28745], [-135.03069, 59.56208], [-135.48007, 59.79937], [-136.31566, 59.59083], [-136.22381, 59.55526], [-136.33727, 59.44466], [-136.47323, 59.46617], [-136.52365, 59.16752], [-136.82619, 59.16198], [-137.4925, 58.89415], [-137.60623, 59.24465], [-138.62145, 59.76431], [-138.71149, 59.90728], [-139.05365, 59.99655], [-139.20603, 60.08896], [-139.05831, 60.35205], [-139.68991, 60.33693], [-139.98024, 60.18027], [-140.45648, 60.30919], [-140.5227, 60.22077], [-141.00116, 60.30648], [-140.97446, 84.39275], [-168.25765, 71.99091], [-168.95635, 65.98512]]]]
22289 aliases: ["ID-SM"],
22291 groups: ["035", "142", "UN"],
22293 callingCodes: ["62"]
22296 type: "MultiPolygon",
22297 coordinates: [[[[109.82788, 2.86812], [110.90339, 7.52694], [105.01437, 3.24936], [104.56723, 1.44271], [104.34728, 1.33529], [104.12282, 1.27714], [104.03085, 1.26954], [103.74084, 1.12902], [103.66049, 1.18825], [103.56591, 1.19719], [103.03657, 1.30383], [96.11174, 6.69841], [74.28481, -3.17525], [102.92489, -8.17146], [106.32259, -5.50116], [106.38511, -5.16715], [109.17017, -4.07401], [109.3962, -2.07276], [108.50935, -2.01066], [107.94791, 1.06924], [109.82788, 2.86812]]]]
22304 aliases: ["ID-JW"],
22306 groups: ["035", "142", "UN"],
22308 callingCodes: ["62"]
22311 type: "MultiPolygon",
22312 coordinates: [[[[109.17017, -4.07401], [106.38511, -5.16715], [106.32259, -5.50116], [102.92489, -8.17146], [116.22542, -10.49172], [114.39575, -8.2889], [114.42235, -8.09762], [114.92859, -7.49253], [116.33992, -7.56171], [116.58433, -5.30385], [109.17017, -4.07401]]]]
22318 nameEn: "Kalimantan",
22319 aliases: ["ID-KA"],
22321 groups: ["Q36117", "035", "142", "UN"],
22323 callingCodes: ["62"]
22326 type: "MultiPolygon",
22327 coordinates: [[[[120.02464, 2.83703], [118.06469, 4.16638], [117.67641, 4.16535], [117.47313, 4.18857], [117.25801, 4.35108], [115.90217, 4.37708], [115.58276, 3.93499], [115.53713, 3.14776], [115.11343, 2.82879], [115.1721, 2.49671], [114.80706, 2.21665], [114.80706, 1.92351], [114.57892, 1.5], [114.03788, 1.44787], [113.64677, 1.23933], [113.01448, 1.42832], [113.021, 1.57819], [112.48648, 1.56516], [112.2127, 1.44135], [112.15679, 1.17004], [111.94553, 1.12016], [111.82846, 0.99349], [111.55434, 0.97864], [111.22979, 1.08326], [110.62374, 0.873], [110.49182, 0.88088], [110.35354, 0.98869], [109.66397, 1.60425], [109.66397, 1.79972], [109.57923, 1.80624], [109.53794, 1.91771], [109.62558, 1.99182], [109.82788, 2.86812], [107.94791, 1.06924], [108.50935, -2.01066], [109.3962, -2.07276], [109.17017, -4.07401], [116.58433, -5.30385], [120.02464, 2.83703]]]]
22333 nameEn: "Lesser Sunda Islands",
22334 aliases: ["ID-NU"],
22336 groups: ["035", "142", "UN"],
22338 callingCodes: ["62"]
22341 type: "MultiPolygon",
22342 coordinates: [[[[116.96967, -8.01483], [114.92859, -7.49253], [114.42235, -8.09762], [114.39575, -8.2889], [116.22542, -10.49172], [122.14954, -11.52517], [125.68138, -9.85176], [125.09025, -9.46406], [124.97892, -9.19281], [125.04044, -9.17093], [125.09434, -9.19669], [125.18907, -9.16434], [125.18632, -9.03142], [125.11764, -8.96359], [124.97742, -9.08128], [124.94011, -8.85617], [124.46701, -9.13002], [124.45971, -9.30263], [124.38554, -9.3582], [124.35258, -9.43002], [124.3535, -9.48493], [124.28115, -9.50453], [124.28115, -9.42189], [124.21247, -9.36904], [124.14517, -9.42324], [124.10539, -9.41206], [124.04286, -9.34243], [124.04628, -9.22671], [124.33472, -9.11416], [124.92337, -8.75859], [125.87688, -7.49892], [116.96967, -8.01483]]]]
22348 nameEn: "Sulawesi",
22349 aliases: ["ID-SL"],
22351 groups: ["035", "142", "UN"],
22353 callingCodes: ["62"]
22356 type: "MultiPolygon",
22357 coordinates: [[[[128.34321, 3.90322], [126.69413, 6.02692], [119.56457, 0.90759], [116.58433, -5.30385], [116.33992, -7.56171], [116.96967, -8.01483], [125.87688, -7.49892], [123.78965, -0.86805], [128.34321, 3.90322]]]]
22363 nameEn: "Maluku Islands",
22364 aliases: ["ID-ML"],
22366 groups: ["035", "142", "UN"],
22368 callingCodes: ["62"]
22371 type: "MultiPolygon",
22372 coordinates: [[[[129.63187, 2.21409], [128.34321, 3.90322], [123.78965, -0.86805], [125.87688, -7.49892], [125.58506, -7.95311], [125.87691, -8.31789], [127.42116, -8.22471], [127.55165, -9.05052], [135.49042, -9.2276], [135.35517, -5.01442], [132.8312, -4.70282], [130.8468, -2.61103], [128.40647, -2.30349], [129.71519, -0.24692], [129.63187, 2.21409]]]]
22378 nameEn: "Western New Guinea",
22379 aliases: ["ID-PP"],
22381 groups: ["035", "142", "UN"],
22383 callingCodes: ["62"]
22386 type: "MultiPolygon",
22387 coordinates: [[[[135.49042, -9.2276], [141.01842, -9.35091], [141.01763, -6.90181], [140.90448, -6.85033], [140.85295, -6.72996], [140.99813, -6.3233], [141.02352, 0.08993], [129.63187, 2.21409], [129.71519, -0.24692], [128.40647, -2.30349], [130.8468, -2.61103], [132.8312, -4.70282], [135.35517, -5.01442], [135.49042, -9.2276]]]]
22393 nameEn: "Balearic Islands",
22394 aliases: ["ES-IB"],
22396 groups: ["EU", "039", "150", "UN"],
22397 callingCodes: ["34 971"]
22400 type: "MultiPolygon",
22401 coordinates: [[[[-2.27707, 35.35051], [5.10072, 39.89531], [3.75438, 42.33445], [-2.27707, 35.35051]]]]
22408 aliases: ["ES-CE"],
22410 groups: ["EA", "EU", "015", "002", "UN"],
22411 level: "subterritory",
22412 callingCodes: ["34"]
22415 type: "MultiPolygon",
22416 coordinates: [[[[-5.38491, 35.92591], [-5.37338, 35.88417], [-5.35844, 35.87375], [-5.34379, 35.8711], [-5.21179, 35.90091], [-5.38491, 35.92591]]]]
22423 aliases: ["ES-ML"],
22425 groups: ["EA", "EU", "015", "002", "UN"],
22426 level: "subterritory",
22427 callingCodes: ["34"]
22430 type: "MultiPolygon",
22431 coordinates: [[[[-2.91909, 35.33927], [-2.96038, 35.31609], [-2.96648, 35.30475], [-2.96978, 35.29459], [-2.97035, 35.28852], [-2.96507, 35.28801], [-2.96826, 35.28296], [-2.96516, 35.27967], [-2.95431, 35.2728], [-2.95065, 35.26576], [-2.93893, 35.26737], [-2.92272, 35.27509], [-2.91909, 35.33927]]]]
22439 groups: ["151", "150", "UN"],
22440 level: "subterritory",
22441 callingCodes: ["7"]
22444 type: "MultiPolygon",
22445 coordinates: [[[[33.5, 44], [36.4883, 45.0488], [36.475, 45.2411], [36.5049, 45.3136], [36.6545, 45.3417], [36.6645, 45.4514], [35.0498, 45.7683], [34.9601, 45.7563], [34.7991, 45.8101], [34.8015, 45.9005], [34.7548, 45.907], [34.6668, 45.9714], [34.6086, 45.9935], [34.5589, 45.9935], [34.5201, 45.951], [34.4873, 45.9427], [34.4415, 45.9599], [34.4122, 46.0025], [34.3391, 46.0611], [34.2511, 46.0532], [34.181, 46.068], [34.1293, 46.1049], [34.0731, 46.1177], [34.0527, 46.1084], [33.9155, 46.1594], [33.8523, 46.1986], [33.7972, 46.2048], [33.7405, 46.1855], [33.646, 46.2303], [33.6152, 46.2261], [33.6385, 46.1415], [33.6147, 46.1356], [33.5732, 46.1032], [33.5909, 46.0601], [33.5597, 46.0307], [31.5, 45.5], [33.5, 44]]]]
22450 wikidata: "Q12837",
22452 level: "sharedLandform"
22458 wikidata: "Q14056",
22459 nameEn: "Jan Mayen",
22460 aliases: ["NO-22"],
22462 groups: ["SJ", "154", "150", "UN"],
22463 level: "subterritory"
22466 type: "MultiPolygon",
22467 coordinates: [[[[-9.18243, 72.23144], [-10.71459, 70.09565], [-5.93364, 70.76368], [-9.18243, 72.23144]]]]
22472 wikidata: "Q19188",
22473 nameEn: "Mainland China",
22475 groups: ["030", "142", "UN"],
22476 callingCodes: ["86"]
22479 type: "MultiPolygon",
22480 coordinates: [[[[125.6131, 53.07229], [125.17522, 53.20225], [124.46078, 53.21881], [123.86158, 53.49391], [123.26989, 53.54843], [122.85966, 53.47395], [122.35063, 53.49565], [121.39213, 53.31888], [120.85633, 53.28499], [120.0451, 52.7359], [120.04049, 52.58773], [120.46454, 52.63811], [120.71673, 52.54099], [120.61346, 52.32447], [120.77337, 52.20805], [120.65907, 51.93544], [120.10963, 51.671], [119.13553, 50.37412], [119.38598, 50.35162], [119.27996, 50.13348], [119.11003, 50.00276], [118.61623, 49.93809], [117.82343, 49.52696], [117.48208, 49.62324], [117.27597, 49.62544], [116.71193, 49.83813], [116.03781, 48.87014], [116.06565, 48.81716], [115.78876, 48.51781], [115.811, 48.25699], [115.52082, 48.15367], [115.57128, 47.91988], [115.94296, 47.67741], [116.21879, 47.88505], [116.4465, 47.83662], [116.67405, 47.89039], [116.9723, 47.87285], [117.37875, 47.63627], [117.50181, 47.77216], [117.80196, 48.01661], [118.03676, 48.00982], [118.11009, 48.04], [118.22677, 48.03853], [118.29654, 48.00246], [118.55766, 47.99277], [118.7564, 47.76947], [119.12343, 47.66458], [119.13995, 47.53997], [119.35892, 47.48104], [119.31964, 47.42617], [119.54918, 47.29505], [119.56019, 47.24874], [119.62403, 47.24575], [119.71209, 47.19192], [119.85518, 46.92196], [119.91242, 46.90091], [119.89261, 46.66423], [119.80455, 46.67631], [119.77373, 46.62947], [119.68127, 46.59015], [119.65265, 46.62342], [119.42827, 46.63783], [119.32827, 46.61433], [119.24978, 46.64761], [119.10448, 46.65516], [119.00541, 46.74273], [118.92616, 46.72765], [118.89974, 46.77139], [118.8337, 46.77742], [118.78747, 46.68689], [118.30534, 46.73519], [117.69554, 46.50991], [117.60748, 46.59771], [117.41782, 46.57862], [117.36609, 46.36335], [116.83166, 46.38637], [116.75551, 46.33083], [116.58612, 46.30211], [116.26678, 45.96479], [116.24012, 45.8778], [116.27366, 45.78637], [116.16989, 45.68603], [115.60329, 45.44717], [114.94546, 45.37377], [114.74612, 45.43585], [114.54801, 45.38337], [114.5166, 45.27189], [113.70918, 44.72891], [112.74662, 44.86297], [112.4164, 45.06858], [111.98695, 45.09074], [111.76275, 44.98032], [111.40498, 44.3461], [111.96289, 43.81596], [111.93776, 43.68709], [111.79758, 43.6637], [111.59087, 43.51207], [111.0149, 43.3289], [110.4327, 42.78293], [110.08401, 42.6411], [109.89402, 42.63111], [109.452, 42.44842], [109.00679, 42.45302], [108.84489, 42.40246], [107.57258, 42.40898], [107.49681, 42.46221], [107.29755, 42.41395], [107.24774, 42.36107], [106.76517, 42.28741], [105.0123, 41.63188], [104.51667, 41.66113], [104.52258, 41.8706], [103.92804, 41.78246], [102.72403, 42.14675], [102.07645, 42.22519], [101.80515, 42.50074], [100.84979, 42.67087], [100.33297, 42.68231], [99.50671, 42.56535], [97.1777, 42.7964], [96.37926, 42.72055], [96.35658, 42.90363], [95.89543, 43.2528], [95.52594, 43.99353], [95.32891, 44.02407], [95.39772, 44.2805], [95.01191, 44.25274], [94.71959, 44.35284], [94.10003, 44.71016], [93.51161, 44.95964], [91.64048, 45.07408], [90.89169, 45.19667], [90.65114, 45.49314], [90.70907, 45.73437], [91.03026, 46.04194], [90.99672, 46.14207], [90.89639, 46.30711], [91.07696, 46.57315], [91.0147, 46.58171], [91.03649, 46.72916], [90.84035, 46.99525], [90.76108, 46.99399], [90.48542, 47.30438], [90.48854, 47.41826], [90.33598, 47.68303], [90.10871, 47.7375], [90.06512, 47.88177], [89.76624, 47.82745], [89.55453, 48.0423], [89.0711, 47.98528], [88.93186, 48.10263], [88.8011, 48.11302], [88.58316, 48.21893], [88.58939, 48.34531], [87.96361, 48.58478], [88.0788, 48.71436], [87.73822, 48.89582], [87.88171, 48.95853], [87.81333, 49.17354], [87.48983, 49.13794], [87.478, 49.07403], [87.28386, 49.11626], [86.87238, 49.12432], [86.73568, 48.99918], [86.75343, 48.70331], [86.38069, 48.46064], [85.73581, 48.3939], [85.5169, 48.05493], [85.61067, 47.49753], [85.69696, 47.2898], [85.54294, 47.06171], [85.22443, 47.04816], [84.93995, 46.87399], [84.73077, 47.01394], [83.92184, 46.98912], [83.04622, 47.19053], [82.21792, 45.56619], [82.58474, 45.40027], [82.51374, 45.1755], [81.73278, 45.3504], [80.11169, 45.03352], [79.8987, 44.89957], [80.38384, 44.63073], [80.40229, 44.23319], [80.40031, 44.10986], [80.75156, 43.44948], [80.69718, 43.32589], [80.77771, 43.30065], [80.78817, 43.14235], [80.62913, 43.141], [80.3735, 43.01557], [80.58999, 42.9011], [80.38169, 42.83142], [80.26886, 42.8366], [80.16892, 42.61137], [80.26841, 42.23797], [80.17807, 42.21166], [80.17842, 42.03211], [79.92977, 42.04113], [78.3732, 41.39603], [78.15757, 41.38565], [78.12873, 41.23091], [77.81287, 41.14307], [77.76206, 41.01574], [77.52723, 41.00227], [77.3693, 41.0375], [77.28004, 41.0033], [76.99302, 41.0696], [76.75681, 40.95354], [76.5261, 40.46114], [76.33659, 40.3482], [75.96168, 40.38064], [75.91361, 40.2948], [75.69663, 40.28642], [75.5854, 40.66874], [75.22834, 40.45382], [75.08243, 40.43945], [74.82013, 40.52197], [74.78168, 40.44886], [74.85996, 40.32857], [74.69875, 40.34668], [74.35063, 40.09742], [74.25533, 40.13191], [73.97049, 40.04378], [73.83006, 39.76136], [73.9051, 39.75073], [73.92354, 39.69565], [73.94683, 39.60733], [73.87018, 39.47879], [73.59831, 39.46425], [73.59241, 39.40843], [73.5004, 39.38402], [73.55396, 39.3543], [73.54572, 39.27567], [73.60638, 39.24534], [73.75823, 39.023], [73.81728, 39.04007], [73.82964, 38.91517], [73.7445, 38.93867], [73.7033, 38.84782], [73.80656, 38.66449], [73.79806, 38.61106], [73.97933, 38.52945], [74.17022, 38.65504], [74.51217, 38.47034], [74.69619, 38.42947], [74.69894, 38.22155], [74.80331, 38.19889], [74.82665, 38.07359], [74.9063, 38.03033], [74.92416, 37.83428], [75.00935, 37.77486], [74.8912, 37.67576], [74.94338, 37.55501], [75.06011, 37.52779], [75.15899, 37.41443], [75.09719, 37.37297], [75.12328, 37.31839], [74.88887, 37.23275], [74.80605, 37.21565], [74.49981, 37.24518], [74.56453, 37.03023], [75.13839, 37.02622], [75.40481, 36.95382], [75.45562, 36.71971], [75.72737, 36.7529], [75.92391, 36.56986], [76.0324, 36.41198], [76.00906, 36.17511], [75.93028, 36.13136], [76.15325, 35.9264], [76.14913, 35.82848], [76.33453, 35.84296], [76.50961, 35.8908], [76.77323, 35.66062], [76.84539, 35.67356], [76.96624, 35.5932], [77.44277, 35.46132], [77.70232, 35.46244], [77.80532, 35.52058], [78.11664, 35.48022], [78.03466, 35.3785], [78.00033, 35.23954], [78.22692, 34.88771], [78.18435, 34.7998], [78.27781, 34.61484], [78.54964, 34.57283], [78.56475, 34.50835], [78.74465, 34.45174], [79.05364, 34.32482], [78.99802, 34.3027], [78.91769, 34.15452], [78.66225, 34.08858], [78.65657, 34.03195], [78.73367, 34.01121], [78.77349, 33.73871], [78.67599, 33.66445], [78.73636, 33.56521], [79.15252, 33.17156], [79.14016, 33.02545], [79.46562, 32.69668], [79.26768, 32.53277], [79.13174, 32.47766], [79.0979, 32.38051], [78.99322, 32.37948], [78.96713, 32.33655], [78.7831, 32.46873], [78.73916, 32.69438], [78.38897, 32.53938], [78.4645, 32.45367], [78.49609, 32.2762], [78.68754, 32.10256], [78.74404, 32.00384], [78.78036, 31.99478], [78.69933, 31.78723], [78.84516, 31.60631], [78.71032, 31.50197], [78.77898, 31.31209], [78.89344, 31.30481], [79.01931, 31.42817], [79.14016, 31.43403], [79.30694, 31.17357], [79.59884, 30.93943], [79.93255, 30.88288], [80.20721, 30.58541], [80.54504, 30.44936], [80.83343, 30.32023], [81.03953, 30.20059], [81.12842, 30.01395], [81.24362, 30.0126], [81.29032, 30.08806], [81.2623, 30.14596], [81.33355, 30.15303], [81.39928, 30.21862], [81.41018, 30.42153], [81.5459, 30.37688], [81.62033, 30.44703], [81.99082, 30.33423], [82.10135, 30.35439], [82.10757, 30.23745], [82.19475, 30.16884], [82.16984, 30.0692], [82.38622, 30.02608], [82.5341, 29.9735], [82.73024, 29.81695], [83.07116, 29.61957], [83.28131, 29.56813], [83.44787, 29.30513], [83.63156, 29.16249], [83.82303, 29.30513], [83.97559, 29.33091], [84.18107, 29.23451], [84.24801, 29.02783], [84.2231, 28.89571], [84.47528, 28.74023], [84.62317, 28.73887], [84.85511, 28.58041], [85.06059, 28.68562], [85.19135, 28.62825], [85.18668, 28.54076], [85.10729, 28.34092], [85.38127, 28.28336], [85.4233, 28.32996], [85.59765, 28.30529], [85.60854, 28.25045], [85.69105, 28.38475], [85.71907, 28.38064], [85.74864, 28.23126], [85.84672, 28.18187], [85.90743, 28.05144], [85.97813, 27.99023], [85.94946, 27.9401], [86.06309, 27.90021], [86.12069, 27.93047], [86.08333, 28.02121], [86.088, 28.09264], [86.18607, 28.17364], [86.22966, 27.9786], [86.42736, 27.91122], [86.51609, 27.96623], [86.56265, 28.09569], [86.74181, 28.10638], [86.75582, 28.04182], [87.03757, 27.94835], [87.11696, 27.84104], [87.56996, 27.84517], [87.72718, 27.80938], [87.82681, 27.95248], [88.13378, 27.88015], [88.1278, 27.95417], [88.25332, 27.9478], [88.54858, 28.06057], [88.63235, 28.12356], [88.83559, 28.01936], [88.88091, 27.85192], [88.77517, 27.45415], [88.82981, 27.38814], [88.91901, 27.32483], [88.93678, 27.33777], [88.96947, 27.30319], [89.00216, 27.32532], [88.95355, 27.4106], [88.97213, 27.51671], [89.0582, 27.60985], [89.12825, 27.62502], [89.59525, 28.16433], [89.79762, 28.23979], [90.13387, 28.19178], [90.58842, 28.02838], [90.69894, 28.07784], [91.20019, 27.98715], [91.25779, 28.07509], [91.46327, 28.0064], [91.48973, 27.93903], [91.5629, 27.84823], [91.6469, 27.76358], [91.84722, 27.76325], [91.87057, 27.7195], [92.27432, 27.89077], [92.32101, 27.79363], [92.42538, 27.80092], [92.7275, 27.98662], [92.73025, 28.05814], [92.65472, 28.07632], [92.67486, 28.15018], [92.93075, 28.25671], [93.14635, 28.37035], [93.18069, 28.50319], [93.44621, 28.67189], [93.72797, 28.68821], [94.35897, 29.01965], [94.2752, 29.11687], [94.69318, 29.31739], [94.81353, 29.17804], [95.0978, 29.14446], [95.11291, 29.09527], [95.2214, 29.10727], [95.26122, 29.07727], [95.3038, 29.13847], [95.41091, 29.13007], [95.50842, 29.13487], [95.72086, 29.20797], [95.75149, 29.32063], [95.84899, 29.31464], [96.05361, 29.38167], [96.31316, 29.18643], [96.18682, 29.11087], [96.20467, 29.02325], [96.3626, 29.10607], [96.61391, 28.72742], [96.40929, 28.51526], [96.48895, 28.42955], [96.6455, 28.61657], [96.85561, 28.4875], [96.88445, 28.39452], [96.98882, 28.32564], [97.1289, 28.3619], [97.34547, 28.21385], [97.41729, 28.29783], [97.47085, 28.2688], [97.50518, 28.49716], [97.56835, 28.55628], [97.70705, 28.5056], [97.79632, 28.33168], [97.90069, 28.3776], [98.15337, 28.12114], [98.13964, 27.9478], [98.32641, 27.51385], [98.42529, 27.55404], [98.43353, 27.67086], [98.69582, 27.56499], [98.7333, 26.85615], [98.77547, 26.61994], [98.72741, 26.36183], [98.67797, 26.24487], [98.7329, 26.17218], [98.66884, 26.09165], [98.63128, 26.15492], [98.57085, 26.11547], [98.60763, 26.01512], [98.70818, 25.86241], [98.63128, 25.79937], [98.54064, 25.85129], [98.40606, 25.61129], [98.31268, 25.55307], [98.25774, 25.6051], [98.16848, 25.62739], [98.18084, 25.56298], [98.12591, 25.50722], [98.14925, 25.41547], [97.92541, 25.20815], [97.83614, 25.2715], [97.77023, 25.11492], [97.72216, 25.08508], [97.72903, 24.91332], [97.79949, 24.85655], [97.76481, 24.8289], [97.73127, 24.83015], [97.70181, 24.84557], [97.64354, 24.79171], [97.56648, 24.76475], [97.56383, 24.75535], [97.5542, 24.74943], [97.54675, 24.74202], [97.56525, 24.72838], [97.56286, 24.54535], [97.52757, 24.43748], [97.60029, 24.4401], [97.66998, 24.45288], [97.7098, 24.35658], [97.65624, 24.33781], [97.66723, 24.30027], [97.71941, 24.29652], [97.76799, 24.26365], [97.72998, 24.2302], [97.72799, 24.18883], [97.75305, 24.16902], [97.72903, 24.12606], [97.62363, 24.00506], [97.5247, 23.94032], [97.64667, 23.84574], [97.72302, 23.89288], [97.79456, 23.94836], [97.79416, 23.95663], [97.84328, 23.97603], [97.86545, 23.97723], [97.88811, 23.97446], [97.8955, 23.97758], [97.89676, 23.97931], [97.89683, 23.98389], [97.88814, 23.98605], [97.88414, 23.99405], [97.88616, 24.00463], [97.90998, 24.02094], [97.93951, 24.01953], [97.98691, 24.03897], [97.99583, 24.04932], [98.04709, 24.07616], [98.05302, 24.07408], [98.05671, 24.07961], [98.0607, 24.07812], [98.06703, 24.08028], [98.07806, 24.07988], [98.20666, 24.11406], [98.54476, 24.13119], [98.59256, 24.08371], [98.85319, 24.13042], [98.87998, 24.15624], [98.89632, 24.10612], [98.67797, 23.9644], [98.68209, 23.80492], [98.79607, 23.77947], [98.82933, 23.72921], [98.81775, 23.694], [98.88396, 23.59555], [98.80294, 23.5345], [98.82877, 23.47908], [98.87683, 23.48995], [98.92104, 23.36946], [98.87573, 23.33038], [98.93958, 23.31414], [98.92515, 23.29535], [98.88597, 23.18656], [99.05975, 23.16382], [99.04601, 23.12215], [99.25741, 23.09025], [99.34127, 23.13099], [99.52214, 23.08218], [99.54218, 22.90014], [99.43537, 22.94086], [99.45654, 22.85726], [99.31243, 22.73893], [99.38247, 22.57544], [99.37972, 22.50188], [99.28771, 22.4105], [99.17318, 22.18025], [99.19176, 22.16983], [99.1552, 22.15874], [99.33166, 22.09656], [99.47585, 22.13345], [99.85351, 22.04183], [99.96612, 22.05965], [99.99084, 21.97053], [99.94003, 21.82782], [99.98654, 21.71064], [100.04956, 21.66843], [100.12679, 21.70539], [100.17486, 21.65306], [100.10757, 21.59945], [100.12542, 21.50365], [100.1625, 21.48704], [100.18447, 21.51898], [100.25863, 21.47043], [100.35201, 21.53176], [100.42892, 21.54325], [100.4811, 21.46148], [100.57861, 21.45637], [100.72143, 21.51898], [100.87265, 21.67396], [101.11744, 21.77659], [101.15156, 21.56129], [101.2124, 21.56422], [101.19349, 21.41959], [101.26912, 21.36482], [101.2229, 21.23271], [101.29326, 21.17254], [101.54563, 21.25668], [101.6068, 21.23329], [101.59491, 21.18621], [101.60886, 21.17947], [101.66977, 21.20004], [101.70548, 21.14911], [101.7622, 21.14813], [101.79266, 21.19025], [101.76745, 21.21571], [101.83887, 21.20983], [101.84412, 21.25291], [101.74014, 21.30967], [101.74224, 21.48276], [101.7727, 21.51794], [101.7475, 21.5873], [101.80001, 21.57461], [101.83257, 21.61562], [101.74555, 21.72852], [101.7791, 21.83019], [101.62566, 21.96574], [101.57525, 22.13026], [101.60675, 22.13513], [101.53638, 22.24794], [101.56789, 22.28876], [101.61306, 22.27515], [101.68973, 22.46843], [101.7685, 22.50337], [101.86828, 22.38397], [101.90714, 22.38688], [101.91344, 22.44417], [101.98487, 22.42766], [102.03633, 22.46164], [102.1245, 22.43372], [102.14099, 22.40092], [102.16621, 22.43336], [102.26428, 22.41321], [102.25339, 22.4607], [102.41061, 22.64184], [102.38415, 22.67919], [102.42618, 22.69212], [102.46665, 22.77108], [102.51802, 22.77969], [102.57095, 22.7036], [102.60675, 22.73376], [102.8636, 22.60735], [102.9321, 22.48659], [103.0722, 22.44775], [103.07843, 22.50097], [103.17961, 22.55705], [103.15782, 22.59873], [103.18895, 22.64471], [103.28079, 22.68063], [103.32282, 22.8127], [103.43179, 22.75816], [103.43646, 22.70648], [103.52675, 22.59155], [103.57812, 22.65764], [103.56255, 22.69499], [103.64506, 22.79979], [103.87904, 22.56683], [103.93286, 22.52703], [103.94513, 22.52553], [103.95191, 22.5134], [103.96352, 22.50584], [103.96783, 22.51173], [103.97384, 22.50634], [103.99247, 22.51958], [104.01088, 22.51823], [104.03734, 22.72945], [104.11384, 22.80363], [104.27084, 22.8457], [104.25683, 22.76534], [104.35593, 22.69353], [104.47225, 22.75813], [104.58122, 22.85571], [104.60457, 22.81841], [104.65283, 22.83419], [104.72755, 22.81984], [104.77114, 22.90017], [104.84942, 22.93631], [104.86765, 22.95178], [104.8334, 23.01484], [104.79478, 23.12934], [104.87382, 23.12854], [104.87992, 23.17141], [104.91435, 23.18666], [104.9486, 23.17235], [104.96532, 23.20463], [104.98712, 23.19176], [105.07002, 23.26248], [105.11672, 23.25247], [105.17276, 23.28679], [105.22569, 23.27249], [105.32376, 23.39684], [105.40782, 23.28107], [105.42805, 23.30824], [105.49966, 23.20669], [105.56037, 23.16806], [105.57594, 23.075], [105.72382, 23.06641], [105.8726, 22.92756], [105.90119, 22.94168], [105.99568, 22.94178], [106.00179, 22.99049], [106.19705, 22.98475], [106.27022, 22.87722], [106.34961, 22.86718], [106.49749, 22.91164], [106.51306, 22.94891], [106.55976, 22.92311], [106.60179, 22.92884], [106.6516, 22.86862], [106.6734, 22.89587], [106.71387, 22.88296], [106.71128, 22.85982], [106.78422, 22.81532], [106.81271, 22.8226], [106.83685, 22.8098], [106.82404, 22.7881], [106.76293, 22.73491], [106.72321, 22.63606], [106.71698, 22.58432], [106.65316, 22.5757], [106.61269, 22.60301], [106.58395, 22.474], [106.55665, 22.46498], [106.57221, 22.37], [106.55976, 22.34841], [106.6516, 22.33977], [106.69986, 22.22309], [106.67495, 22.1885], [106.6983, 22.15102], [106.70142, 22.02409], [106.68274, 21.99811], [106.69276, 21.96013], [106.72551, 21.97923], [106.74345, 22.00965], [106.81038, 21.97934], [106.9178, 21.97357], [106.92714, 21.93459], [106.97228, 21.92592], [106.99252, 21.95191], [107.05634, 21.92303], [107.06101, 21.88982], [107.00964, 21.85948], [107.02615, 21.81981], [107.10771, 21.79879], [107.20734, 21.71493], [107.24625, 21.7077], [107.29296, 21.74674], [107.35834, 21.6672], [107.35989, 21.60063], [107.38636, 21.59774], [107.41593, 21.64839], [107.47197, 21.6672], [107.49532, 21.62958], [107.49065, 21.59774], [107.54047, 21.5934], [107.56537, 21.61945], [107.66967, 21.60787], [107.80355, 21.66141], [107.86114, 21.65128], [107.90006, 21.5905], [107.92652, 21.58906], [107.95232, 21.5388], [107.96774, 21.53601], [107.97074, 21.54072], [107.97383, 21.53961], [107.97932, 21.54503], [108.02926, 21.54997], [108.0569, 21.53604], [108.10003, 21.47338], [108.00365, 17.98159], [111.60491, 13.57105], [118.41371, 24.06775], [118.11703, 24.39734], [118.28244, 24.51231], [118.35291, 24.51645], [118.42453, 24.54644], [118.56434, 24.49266], [120.49232, 25.22863], [121.03532, 26.8787], [123.5458, 31.01942], [122.29378, 31.76513], [122.80525, 33.30571], [123.85601, 37.49093], [123.90497, 38.79949], [124.17532, 39.8232], [124.23201, 39.9248], [124.35029, 39.95639], [124.37089, 40.03004], [124.3322, 40.05573], [124.38556, 40.11047], [124.40719, 40.13655], [124.86913, 40.45387], [125.71172, 40.85223], [125.76869, 40.87908], [126.00335, 40.92835], [126.242, 41.15454], [126.53189, 41.35206], [126.60631, 41.65565], [126.90729, 41.79955], [127.17841, 41.59714], [127.29712, 41.49473], [127.92943, 41.44291], [128.02633, 41.42103], [128.03311, 41.39232], [128.12967, 41.37931], [128.18546, 41.41279], [128.20061, 41.40895], [128.30716, 41.60322], [128.15119, 41.74568], [128.04487, 42.01769], [128.94007, 42.03537], [128.96068, 42.06657], [129.15178, 42.17224], [129.22285, 42.26491], [129.22423, 42.3553], [129.28541, 42.41574], [129.42882, 42.44702], [129.54701, 42.37254], [129.60482, 42.44461], [129.72541, 42.43739], [129.75294, 42.59409], [129.77183, 42.69435], [129.7835, 42.76521], [129.80719, 42.79218], [129.83277, 42.86746], [129.85261, 42.96494], [129.8865, 43.00395], [129.95082, 43.01051], [129.96409, 42.97306], [130.12957, 42.98361], [130.09764, 42.91425], [130.26095, 42.9027], [130.23068, 42.80125], [130.2385, 42.71127], [130.41826, 42.6011], [130.44361, 42.54849], [130.50123, 42.61636], [130.55143, 42.52158], [130.62107, 42.58413], [130.56576, 42.68925], [130.40213, 42.70788], [130.44361, 42.76205], [130.66524, 42.84753], [131.02438, 42.86518], [131.02668, 42.91246], [131.135, 42.94114], [131.10274, 43.04734], [131.20414, 43.13654], [131.19031, 43.21385], [131.30324, 43.39498], [131.29402, 43.46695], [131.19492, 43.53047], [131.21105, 43.82383], [131.26176, 43.94011], [131.23583, 43.96085], [131.25484, 44.03131], [131.30365, 44.04262], [131.1108, 44.70266], [130.95639, 44.85154], [131.48415, 44.99513], [131.68466, 45.12374], [131.66852, 45.2196], [131.76532, 45.22609], [131.86903, 45.33636], [131.99417, 45.2567], [132.83978, 45.05916], [132.96373, 45.0212], [133.12293, 45.1332], [133.09279, 45.25693], [133.19419, 45.51913], [133.41083, 45.57723], [133.48457, 45.86203], [133.60442, 45.90053], [133.67569, 45.9759], [133.72695, 46.05576], [133.68047, 46.14697], [133.88097, 46.25066], [133.91496, 46.4274], [133.84104, 46.46681], [134.03538, 46.75668], [134.20016, 47.33458], [134.50898, 47.4812], [134.7671, 47.72051], [134.55508, 47.98651], [134.67098, 48.1564], [134.75328, 48.36763], [134.49516, 48.42884], [132.66989, 47.96491], [132.57309, 47.71741], [131.90448, 47.68011], [131.2635, 47.73325], [131.09871, 47.6852], [130.95985, 47.6957], [130.90915, 47.90623], [130.65103, 48.10052], [130.84462, 48.30942], [130.52147, 48.61745], [130.66946, 48.88251], [130.43232, 48.90844], [130.2355, 48.86741], [129.85416, 49.11067], [129.67598, 49.29596], [129.50685, 49.42398], [129.40398, 49.44194], [129.35317, 49.3481], [129.23232, 49.40353], [129.11153, 49.36813], [128.72896, 49.58676], [127.83476, 49.5748], [127.53516, 49.84306], [127.49299, 50.01251], [127.60515, 50.23503], [127.37384, 50.28393], [127.36009, 50.43787], [127.28765, 50.46585], [127.36335, 50.58306], [127.28165, 50.72075], [127.14586, 50.91152], [126.93135, 51.0841], [126.90369, 51.3238], [126.68349, 51.70607], [126.44606, 51.98254], [126.558, 52.13738], [125.6131, 53.07229]], [[113.56865, 22.20973], [113.57123, 22.20416], [113.60504, 22.20464], [113.63011, 22.10782], [113.57191, 22.07696], [113.54839, 22.10909], [113.54942, 22.14519], [113.54093, 22.15497], [113.52659, 22.18271], [113.53552, 22.20607], [113.53301, 22.21235], [113.53591, 22.21369], [113.54093, 22.21314], [113.54333, 22.21688], [113.5508, 22.21672], [113.56865, 22.20973]], [[114.50148, 22.15017], [113.92195, 22.13873], [113.83338, 22.1826], [113.81621, 22.2163], [113.86771, 22.42972], [114.03113, 22.5065], [114.05438, 22.5026], [114.05729, 22.51104], [114.06272, 22.51617], [114.07267, 22.51855], [114.07817, 22.52997], [114.08606, 22.53276], [114.09048, 22.53716], [114.09692, 22.53435], [114.1034, 22.5352], [114.11181, 22.52878], [114.11656, 22.53415], [114.12665, 22.54003], [114.13823, 22.54319], [114.1482, 22.54091], [114.15123, 22.55163], [114.1597, 22.56041], [114.17247, 22.55944], [114.18338, 22.55444], [114.20655, 22.55706], [114.22185, 22.55343], [114.22888, 22.5436], [114.25154, 22.55977], [114.44998, 22.55977], [114.50148, 22.15017]]]]
22485 wikidata: "Q22890",
22487 level: "sharedLandform"
22493 wikidata: "Q23666",
22494 nameEn: "Great Britain",
22496 level: "sharedLandform"
22502 wikidata: "Q23681",
22503 nameEn: "Northern Cyprus",
22504 groups: ["Q644636", "145", "142"],
22506 callingCodes: ["90 392"]
22509 type: "MultiPolygon",
22510 coordinates: [[[[33.67678, 35.03866], [33.67742, 35.05963], [33.68474, 35.06602], [33.69095, 35.06237], [33.70861, 35.07644], [33.7161, 35.07279], [33.70209, 35.04882], [33.71482, 35.03722], [33.73824, 35.05321], [33.76106, 35.04253], [33.78581, 35.05104], [33.82067, 35.07826], [33.84168, 35.06823], [33.8541, 35.07201], [33.87479, 35.08881], [33.87097, 35.09389], [33.87622, 35.10457], [33.87224, 35.12293], [33.88561, 35.12449], [33.88943, 35.12007], [33.88737, 35.11408], [33.89853, 35.11377], [33.91789, 35.08688], [33.91299, 35.07579], [33.90247, 35.07686], [33.89485, 35.06873], [33.88367, 35.07877], [33.85261, 35.0574], [33.8355, 35.05777], [33.82051, 35.0667], [33.8012, 35.04786], [33.81524, 35.04192], [33.83055, 35.02865], [33.82875, 35.01685], [33.84045, 35.00616], [33.85216, 35.00579], [33.85891, 35.001], [33.85621, 34.98956], [33.83505, 34.98108], [33.84811, 34.97075], [33.86432, 34.97592], [33.90075, 34.96623], [33.98684, 34.76642], [35.48515, 34.70851], [35.51152, 36.10954], [32.82353, 35.70297], [32.46489, 35.48584], [32.60361, 35.16647], [32.64864, 35.19967], [32.70947, 35.18328], [32.70779, 35.14127], [32.85733, 35.07742], [32.86406, 35.1043], [32.94471, 35.09422], [33.01192, 35.15639], [33.08249, 35.17319], [33.11105, 35.15639], [33.15138, 35.19504], [33.27068, 35.16815], [33.3072, 35.16816], [33.31955, 35.18096], [33.35056, 35.18328], [33.34964, 35.17803], [33.35596, 35.17942], [33.35612, 35.17402], [33.36569, 35.17479], [33.3717, 35.1788], [33.37248, 35.18698], [33.38575, 35.2018], [33.4076, 35.20062], [33.41675, 35.16325], [33.46813, 35.10564], [33.48136, 35.0636], [33.47825, 35.04103], [33.45178, 35.02078], [33.45256, 35.00288], [33.47666, 35.00701], [33.48915, 35.06594], [33.53975, 35.08151], [33.57478, 35.06049], [33.567, 35.04803], [33.59658, 35.03635], [33.61215, 35.0527], [33.63765, 35.03869], [33.67678, 35.03866]]]]
22515 wikidata: "Q25231",
22516 nameEn: "Svalbard",
22517 aliases: ["NO-21"],
22519 groups: ["SJ", "154", "150", "UN"],
22520 level: "subterritory",
22521 callingCodes: ["47 79"]
22524 type: "MultiPolygon",
22525 coordinates: [[[[-7.49892, 77.24208], [32.07813, 72.01005], [36.85549, 84.09565], [-7.49892, 77.24208]]]]
22530 wikidata: "Q25263",
22532 aliases: ["PT-20"],
22534 groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
22535 callingCodes: ["351"]
22538 type: "MultiPolygon",
22539 coordinates: [[[[-23.12984, 40.26428], [-36.43765, 41.39418], [-22.54767, 33.34416], [-23.12984, 40.26428]]]]
22544 wikidata: "Q25359",
22545 nameEn: "Navassa Island",
22546 aliases: ["UM-76"],
22548 groups: ["UM", "Q1352230", "029", "003", "419", "019", "UN"],
22549 level: "subterritory",
22550 roadSpeedUnit: "mph",
22551 roadHeightUnit: "ft"
22554 type: "MultiPolygon",
22555 coordinates: [[[[-74.7289, 18.71009], [-75.71816, 18.46438], [-74.76465, 18.06252], [-74.7289, 18.71009]]]]
22560 wikidata: "Q25396",
22562 aliases: ["BQ-BO", "NL-BQ1"],
22564 groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22565 level: "subterritory",
22566 callingCodes: ["599 7"]
22569 type: "MultiPolygon",
22570 coordinates: [[[[-67.89186, 12.4116], [-68.90012, 12.62309], [-68.33524, 11.78151], [-68.01417, 11.77722], [-67.89186, 12.4116]]]]
22575 wikidata: "Q25528",
22577 aliases: ["BQ-SA", "NL-BQ2"],
22579 groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22580 level: "subterritory",
22581 callingCodes: ["599 4"]
22584 type: "MultiPolygon",
22585 coordinates: [[[[-63.07669, 17.79659], [-63.81314, 17.95045], [-63.22932, 17.32592], [-63.07669, 17.79659]]]]
22590 wikidata: "Q26180",
22591 nameEn: "Sint Eustatius",
22592 aliases: ["BQ-SE", "NL-BQ3"],
22594 groups: ["Q1451600", "BQ", "029", "003", "419", "019", "UN"],
22595 level: "subterritory",
22596 callingCodes: ["599 3"]
22599 type: "MultiPolygon",
22600 coordinates: [[[[-63.07669, 17.79659], [-63.34999, 16.94218], [-62.76692, 17.64353], [-63.07669, 17.79659]]]]
22605 wikidata: "Q26253",
22607 aliases: ["PT-30"],
22609 groups: ["Q3320166", "Q2914565", "Q105472", "EU", "039", "150", "UN"],
22610 callingCodes: ["351"]
22613 type: "MultiPolygon",
22614 coordinates: [[[[-19.30302, 33.65304], [-16.04789, 29.65076], [-11.68307, 33.12333], [-19.30302, 33.65304]]]]
22619 wikidata: "Q26927",
22620 nameEn: "Lakshadweep",
22621 aliases: ["IN-LD"],
22623 groups: ["034", "142", "UN"],
22625 callingCodes: ["91"]
22628 type: "MultiPolygon",
22629 coordinates: [[[[67.64074, 11.57295], [76.59015, 5.591], [72.67494, 13.58102], [67.64074, 11.57295]]]]
22634 wikidata: "Q27329",
22635 nameEn: "Asian Russia",
22637 groups: ["142", "UN"],
22638 callingCodes: ["7"]
22641 type: "MultiPolygon",
22642 coordinates: [[[[-179.99933, 64.74703], [-172.76104, 63.77445], [-169.03888, 65.48473], [-168.95635, 65.98512], [-168.25765, 71.99091], [-179.9843, 71.90735], [-179.99933, 64.74703]]], [[[59.99809, 51.98263], [60.19925, 51.99173], [60.48915, 52.15175], [60.72581, 52.15538], [60.78201, 52.22067], [61.05417, 52.35096], [60.98021, 52.50068], [60.84709, 52.52228], [60.84118, 52.63912], [60.71693, 52.66245], [60.71989, 52.75923], [61.05842, 52.92217], [61.23462, 53.03227], [62.0422, 52.96105], [62.12799, 52.99133], [62.14574, 53.09626], [61.19024, 53.30536], [61.14291, 53.41481], [61.29082, 53.50992], [61.37957, 53.45887], [61.57185, 53.50112], [61.55706, 53.57144], [60.90626, 53.62937], [61.22574, 53.80268], [61.14283, 53.90063], [60.99796, 53.93699], [61.26863, 53.92797], [61.3706, 54.08464], [61.47603, 54.08048], [61.56941, 53.95703], [61.65318, 54.02445], [62.03913, 53.94768], [62.00966, 54.04134], [62.38535, 54.03961], [62.45931, 53.90737], [62.56876, 53.94047], [62.58651, 54.05871], [63.80604, 54.27079], [63.91224, 54.20013], [64.02715, 54.22679], [63.97686, 54.29763], [64.97216, 54.4212], [65.11033, 54.33028], [65.24663, 54.35721], [65.20174, 54.55216], [68.21308, 54.98645], [68.26661, 55.09226], [68.19206, 55.18823], [68.90865, 55.38148], [69.34224, 55.36344], [69.74917, 55.35545], [70.19179, 55.1476], [70.76493, 55.3027], [70.96009, 55.10558], [71.08288, 54.71253], [71.24185, 54.64965], [71.08706, 54.33376], [71.10379, 54.13326], [71.96141, 54.17736], [72.17477, 54.36303], [72.43415, 53.92685], [72.71026, 54.1161], [73.37963, 53.96132], [73.74778, 54.07194], [73.68921, 53.86522], [73.25412, 53.61532], [73.39218, 53.44623], [75.07405, 53.80831], [75.43398, 53.98652], [75.3668, 54.07439], [76.91052, 54.4677], [76.82266, 54.1798], [76.44076, 54.16017], [76.54243, 53.99329], [77.90383, 53.29807], [79.11255, 52.01171], [80.08138, 50.77658], [80.4127, 50.95581], [80.44819, 51.20855], [80.80318, 51.28262], [81.16999, 51.15662], [81.06091, 50.94833], [81.41248, 50.97524], [81.46581, 50.77658], [81.94999, 50.79307], [82.55443, 50.75412], [83.14607, 51.00796], [83.8442, 50.87375], [84.29385, 50.27257], [84.99198, 50.06793], [85.24047, 49.60239], [86.18709, 49.50259], [86.63674, 49.80136], [86.79056, 49.74787], [86.61307, 49.60239], [86.82606, 49.51796], [87.03071, 49.25142], [87.31465, 49.23603], [87.28386, 49.11626], [87.478, 49.07403], [87.48983, 49.13794], [87.81333, 49.17354], [87.98977, 49.18147], [88.15543, 49.30314], [88.17223, 49.46934], [88.42449, 49.48821], [88.82499, 49.44808], [89.70687, 49.72535], [89.59711, 49.90851], [91.86048, 50.73734], [92.07173, 50.69585], [92.44714, 50.78762], [93.01109, 50.79001], [92.99595, 50.63183], [94.30823, 50.57498], [94.39258, 50.22193], [94.49477, 50.17832], [94.6121, 50.04239], [94.97166, 50.04725], [95.02465, 49.96941], [95.74757, 49.97915], [95.80056, 50.04239], [96.97388, 49.88413], [97.24639, 49.74737], [97.56811, 49.84265], [97.56432, 49.92801], [97.76871, 49.99861], [97.85197, 49.91339], [98.29481, 50.33561], [98.31373, 50.4996], [98.06393, 50.61262], [97.9693, 50.78044], [98.01472, 50.86652], [97.83305, 51.00248], [98.05257, 51.46696], [98.22053, 51.46579], [98.33222, 51.71832], [98.74142, 51.8637], [98.87768, 52.14563], [99.27888, 51.96876], [99.75578, 51.90108], [99.89203, 51.74903], [100.61116, 51.73028], [101.39085, 51.45753], [101.5044, 51.50467], [102.14032, 51.35566], [102.32194, 50.67982], [102.71178, 50.38873], [103.70343, 50.13952], [105.32528, 50.4648], [106.05562, 50.40582], [106.07865, 50.33474], [106.47156, 50.31909], [106.49628, 50.32436], [106.51122, 50.34408], [106.58373, 50.34044], [106.80326, 50.30177], [107.00007, 50.1977], [107.1174, 50.04239], [107.36407, 49.97612], [107.96116, 49.93191], [107.95387, 49.66659], [108.27937, 49.53167], [108.53969, 49.32325], [109.18017, 49.34709], [109.51325, 49.22859], [110.24373, 49.16676], [110.39891, 49.25083], [110.64493, 49.1816], [113.02647, 49.60772], [113.20216, 49.83356], [114.325, 50.28098], [114.9703, 50.19254], [115.26068, 49.97367], [115.73602, 49.87688], [116.22402, 50.04477], [116.62502, 49.92919], [116.71193, 49.83813], [117.27597, 49.62544], [117.48208, 49.62324], [117.82343, 49.52696], [118.61623, 49.93809], [119.11003, 50.00276], [119.27996, 50.13348], [119.38598, 50.35162], [119.13553, 50.37412], [120.10963, 51.671], [120.65907, 51.93544], [120.77337, 52.20805], [120.61346, 52.32447], [120.71673, 52.54099], [120.46454, 52.63811], [120.04049, 52.58773], [120.0451, 52.7359], [120.85633, 53.28499], [121.39213, 53.31888], [122.35063, 53.49565], [122.85966, 53.47395], [123.26989, 53.54843], [123.86158, 53.49391], [124.46078, 53.21881], [125.17522, 53.20225], [125.6131, 53.07229], [126.558, 52.13738], [126.44606, 51.98254], [126.68349, 51.70607], [126.90369, 51.3238], [126.93135, 51.0841], [127.14586, 50.91152], [127.28165, 50.72075], [127.36335, 50.58306], [127.28765, 50.46585], [127.36009, 50.43787], [127.37384, 50.28393], [127.60515, 50.23503], [127.49299, 50.01251], [127.53516, 49.84306], [127.83476, 49.5748], [128.72896, 49.58676], [129.11153, 49.36813], [129.23232, 49.40353], [129.35317, 49.3481], [129.40398, 49.44194], [129.50685, 49.42398], [129.67598, 49.29596], [129.85416, 49.11067], [130.2355, 48.86741], [130.43232, 48.90844], [130.66946, 48.88251], [130.52147, 48.61745], [130.84462, 48.30942], [130.65103, 48.10052], [130.90915, 47.90623], [130.95985, 47.6957], [131.09871, 47.6852], [131.2635, 47.73325], [131.90448, 47.68011], [132.57309, 47.71741], [132.66989, 47.96491], [134.49516, 48.42884], [134.75328, 48.36763], [134.67098, 48.1564], [134.55508, 47.98651], [134.7671, 47.72051], [134.50898, 47.4812], [134.20016, 47.33458], [134.03538, 46.75668], [133.84104, 46.46681], [133.91496, 46.4274], [133.88097, 46.25066], [133.68047, 46.14697], [133.72695, 46.05576], [133.67569, 45.9759], [133.60442, 45.90053], [133.48457, 45.86203], [133.41083, 45.57723], [133.19419, 45.51913], [133.09279, 45.25693], [133.12293, 45.1332], [132.96373, 45.0212], [132.83978, 45.05916], [131.99417, 45.2567], [131.86903, 45.33636], [131.76532, 45.22609], [131.66852, 45.2196], [131.68466, 45.12374], [131.48415, 44.99513], [130.95639, 44.85154], [131.1108, 44.70266], [131.30365, 44.04262], [131.25484, 44.03131], [131.23583, 43.96085], [131.26176, 43.94011], [131.21105, 43.82383], [131.19492, 43.53047], [131.29402, 43.46695], [131.30324, 43.39498], [131.19031, 43.21385], [131.20414, 43.13654], [131.10274, 43.04734], [131.135, 42.94114], [131.02668, 42.91246], [131.02438, 42.86518], [130.66524, 42.84753], [130.44361, 42.76205], [130.40213, 42.70788], [130.56576, 42.68925], [130.62107, 42.58413], [130.55143, 42.52158], [130.56835, 42.43281], [130.60805, 42.4317], [130.64181, 42.41422], [130.66367, 42.38024], [130.65022, 42.32281], [131.95041, 41.5445], [140.9182, 45.92937], [145.82343, 44.571], [145.23667, 43.76813], [153.94307, 38.42848], [180, 62.52334], [180, 71.53642], [155.31937, 81.93282], [76.13964, 83.37843], [64.18965, 69.94255], [66.1708, 67.61252], [61.98014, 65.72191], [60.74386, 64.95767], [59.63945, 64.78384], [59.80579, 64.13948], [59.24834, 63.01859], [59.61398, 62.44915], [59.36223, 61.3882], [59.50685, 60.91162], [58.3853, 59.487], [59.15636, 59.14682], [59.40376, 58.45822], [58.71104, 58.07475], [58.81412, 57.71602], [58.13789, 57.68097], [58.07604, 57.08308], [57.28024, 56.87898], [57.51527, 56.08729], [59.28419, 56.15739], [59.49035, 55.60486], [58.81825, 55.03378], [57.25137, 55.26262], [57.14829, 54.84204], [57.95234, 54.39672], [59.95217, 54.85853], [59.70487, 54.14846], [58.94336, 53.953], [58.79644, 52.43392], [59.22409, 52.28437], [59.25033, 52.46803], [60.17516, 52.39457], [60.17253, 52.25814], [59.91279, 52.06924], [59.99809, 51.98263]]]]
22647 wikidata: "Q34366",
22648 nameEn: "Tasmania",
22649 aliases: ["AU-TAS"],
22651 groups: ["053", "009", "UN"],
22653 callingCodes: ["61"]
22656 type: "MultiPolygon",
22657 coordinates: [[[[123.64533, -39.13605], [159.69067, -56.28945], [159.74028, -39.1978], [123.64533, -39.13605]]]]
22662 wikidata: "Q34497",
22663 nameEn: "Saint Helena",
22664 aliases: ["SH-HL"],
22666 groups: ["SH", "BOTS", "011", "202", "002", "UN"],
22667 level: "subterritory",
22669 roadSpeedUnit: "mph",
22670 roadHeightUnit: "ft",
22671 callingCodes: ["290"]
22674 type: "MultiPolygon",
22675 coordinates: [[[[-8.3824, -13.9131], [-6.17428, -19.07236], [-3.29308, -15.22647], [-8.3824, -13.9131]]]]
22680 wikidata: "Q35657",
22681 nameEn: "US States",
22683 level: "subcountryGroup"
22689 wikidata: "Q36117",
22691 level: "sharedLandform"
22697 wikidata: "Q36678",
22698 nameEn: "West Bank",
22700 groups: ["145", "142"],
22701 callingCodes: ["970"]
22704 type: "MultiPolygon",
22705 coordinates: [[[[35.47672, 31.49578], [35.55941, 31.76535], [35.52758, 31.9131], [35.54375, 31.96587], [35.52012, 32.04076], [35.57111, 32.21877], [35.55807, 32.38674], [35.42078, 32.41562], [35.41048, 32.43706], [35.41598, 32.45593], [35.42034, 32.46009], [35.40224, 32.50136], [35.35212, 32.52047], [35.30685, 32.51024], [35.29306, 32.50947], [35.25049, 32.52453], [35.2244, 32.55289], [35.15937, 32.50466], [35.10882, 32.4757], [35.10024, 32.47856], [35.09236, 32.47614], [35.08564, 32.46948], [35.07059, 32.4585], [35.05423, 32.41754], [35.05311, 32.4024], [35.0421, 32.38242], [35.05142, 32.3667], [35.04243, 32.35008], [35.01772, 32.33863], [35.01119, 32.28684], [35.02939, 32.2671], [35.01841, 32.23981], [34.98885, 32.20758], [34.95703, 32.19522], [34.96009, 32.17503], [34.99039, 32.14626], [34.98507, 32.12606], [34.99437, 32.10962], [34.9863, 32.09551], [35.00261, 32.027], [34.98682, 31.96935], [35.00124, 31.93264], [35.03489, 31.92448], [35.03978, 31.89276], [35.03489, 31.85919], [34.99712, 31.85569], [34.9724, 31.83352], [35.01978, 31.82944], [35.05617, 31.85685], [35.07677, 31.85627], [35.14174, 31.81325], [35.18603, 31.80901], [35.18169, 31.82542], [35.19461, 31.82687], [35.21469, 31.81835], [35.216, 31.83894], [35.21128, 31.863], [35.20381, 31.86716], [35.20673, 31.88151], [35.20791, 31.8821], [35.20945, 31.8815], [35.21016, 31.88237], [35.21276, 31.88153], [35.2136, 31.88241], [35.22014, 31.88264], [35.22294, 31.87889], [35.22567, 31.86745], [35.22817, 31.8638], [35.2249, 31.85433], [35.2304, 31.84222], [35.24816, 31.8458], [35.25753, 31.8387], [35.251, 31.83085], [35.26404, 31.82567], [35.25573, 31.81362], [35.26058, 31.79064], [35.25225, 31.7678], [35.26319, 31.74846], [35.25182, 31.73945], [35.24981, 31.72543], [35.2438, 31.7201], [35.24315, 31.71244], [35.23972, 31.70896], [35.22392, 31.71899], [35.21937, 31.71578], [35.20538, 31.72388], [35.18023, 31.72067], [35.16478, 31.73242], [35.15474, 31.73352], [35.15119, 31.73634], [35.13931, 31.73012], [35.12933, 31.7325], [35.11895, 31.71454], [35.10782, 31.71594], [35.08226, 31.69107], [35.00879, 31.65426], [34.95249, 31.59813], [34.9415, 31.55601], [34.94356, 31.50743], [34.93258, 31.47816], [34.89756, 31.43891], [34.87833, 31.39321], [34.88932, 31.37093], [34.92571, 31.34337], [35.02459, 31.35979], [35.13033, 31.3551], [35.22921, 31.37445], [35.39675, 31.49572], [35.47672, 31.49578]]]]
22710 wikidata: "Q37362",
22711 nameEn: "Akrotiri and Dhekelia",
22719 wikidata: "Q38095",
22720 nameEn: "Gal\xE1pagos Islands",
22723 groups: ["005", "419", "019", "UN"],
22724 callingCodes: ["593"]
22727 type: "MultiPolygon",
22728 coordinates: [[[[-93.12365, 2.64343], [-92.46744, -2.52874], [-87.07749, -0.8849], [-93.12365, 2.64343]]]]
22733 wikidata: "Q39760",
22734 nameEn: "Gaza Strip",
22736 groups: ["145", "142"],
22737 callingCodes: ["970"]
22740 type: "MultiPolygon",
22741 coordinates: [[[[34.052, 31.46619], [34.21853, 31.32363], [34.23572, 31.2966], [34.24012, 31.29591], [34.26742, 31.21998], [34.29417, 31.24194], [34.36523, 31.28963], [34.37381, 31.30598], [34.36505, 31.36404], [34.40077, 31.40926], [34.48892, 31.48365], [34.56797, 31.54197], [34.48681, 31.59711], [34.29262, 31.70393], [34.052, 31.46619]]]]
22746 wikidata: "Q40888",
22747 nameEn: "Andaman and Nicobar Islands",
22748 aliases: ["IN-AN"],
22750 groups: ["034", "142", "UN"],
22752 callingCodes: ["91"]
22755 type: "MultiPolygon",
22756 coordinates: [[[[94.42132, 5.96581], [94.6371, 13.81803], [86.7822, 13.41052], [94.42132, 5.96581]]]]
22761 wikidata: "Q41684",
22762 nameEn: "Stewart Island",
22764 groups: ["053", "009", "UN"],
22766 callingCodes: ["64"]
22769 type: "MultiPolygon",
22770 coordinates: [[[[166.59185, -47.61313], [169.70504, -47.56021], [167.52103, -46.41337], [166.59185, -47.61313]]]]
22775 wikidata: "Q43296",
22776 nameEn: "Wake Island",
22777 aliases: ["WK", "WAK", "WKUM", "872", "UM-79"],
22779 groups: ["UM", "Q1352230", "057", "009", "UN"],
22780 level: "subterritory",
22781 roadSpeedUnit: "mph",
22782 roadHeightUnit: "ft",
22783 callingCodes: ["1"]
22786 type: "MultiPolygon",
22787 coordinates: [[[[167.34779, 18.97692], [166.67967, 20.14834], [165.82549, 18.97692], [167.34779, 18.97692]]]]
22792 wikidata: "Q46275",
22793 nameEn: "New Zealand Subantarctic Islands",
22795 groups: ["Q851132", "053", "009", "UN"],
22799 type: "MultiPolygon",
22800 coordinates: [[[[164.30551, -47.88072], [161.96603, -56.07661], [179.49541, -50.04657], [179.49541, -47.2902], [169.91032, -47.66283], [164.30551, -47.88072]]]]
22805 wikidata: "Q46395",
22806 nameEn: "British Overseas Territories",
22807 aliases: ["BOTS", "UKOTS"],
22809 level: "subcountryGroup"
22815 wikidata: "Q46772",
22816 nameEn: "Kerguelen Islands",
22818 groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
22819 level: "subterritory"
22822 type: "MultiPolygon",
22823 coordinates: [[[[61.9216, -49.39746], [70.67507, -51.14192], [74.25129, -45.45074], [61.9216, -49.39746]]]]
22828 wikidata: "Q46879",
22829 nameEn: "Baker Island",
22830 aliases: ["UM-81"],
22832 groups: ["UM", "Q1352230", "061", "009", "UN"],
22833 level: "subterritory",
22834 roadSpeedUnit: "mph",
22835 roadHeightUnit: "ft"
22838 type: "MultiPolygon",
22839 coordinates: [[[[-175.33482, -1.40631], [-175.31323, 0.5442], [-177.91421, 0.39582], [-175.33482, -1.40631]]]]
22844 wikidata: "Q47863",
22845 nameEn: "Midway Atoll",
22846 aliases: ["MI", "MID", "MIUM", "488", "UM-71"],
22848 groups: ["UM", "Q1352230", "061", "009", "UN"],
22849 level: "subterritory",
22850 roadSpeedUnit: "mph",
22851 roadHeightUnit: "ft",
22852 callingCodes: ["1"]
22855 type: "MultiPolygon",
22856 coordinates: [[[[-176.29741, 29.09786], [-177.77531, 29.29793], [-177.5224, 27.7635], [-176.29741, 29.09786]]]]
22861 wikidata: "Q62218",
22862 nameEn: "Jarvis Island",
22863 aliases: ["UM-86"],
22865 groups: ["UM", "Q1352230", "061", "009", "UN"],
22866 level: "subterritory",
22867 roadSpeedUnit: "mph",
22868 roadHeightUnit: "ft"
22871 type: "MultiPolygon",
22872 coordinates: [[[[-160.42921, -1.4364], [-159.12443, 0.19975], [-160.38779, 0.30331], [-160.42921, -1.4364]]]]
22877 wikidata: "Q105472",
22878 nameEn: "Macaronesia",
22879 level: "sharedLandform"
22885 wikidata: "Q114935",
22886 nameEn: "Kermadec Islands",
22888 groups: ["Q851132", "053", "009", "UN"],
22890 callingCodes: ["64"]
22893 type: "MultiPolygon",
22894 coordinates: [[[[-174.40891, -29.09438], [-180, -24.21376], [-179.96512, -35.00791], [-174.40891, -29.09438]]]]
22899 wikidata: "Q115459",
22900 nameEn: "Chatham Islands",
22901 aliases: ["NZ-CIT"],
22903 groups: ["Q851132", "053", "009", "UN"],
22905 callingCodes: ["64"]
22908 type: "MultiPolygon",
22909 coordinates: [[[[-179.93224, -45.18423], [-172.47015, -45.17912], [-176.30998, -41.38382], [-179.93224, -45.18423]]]]
22914 wikidata: "Q118863",
22915 nameEn: "North Island",
22917 groups: ["053", "009", "UN"],
22919 callingCodes: ["64"]
22922 type: "MultiPolygon",
22923 coordinates: [[[[179.49541, -47.2902], [179.49541, -36.79303], [174.17679, -32.62487], [170.27492, -36.38133], [174.58663, -40.80446], [174.46634, -41.55028], [179.49541, -47.2902]]]]
22928 wikidata: "Q120755",
22929 nameEn: "South Island",
22931 groups: ["053", "009", "UN"],
22933 callingCodes: ["64"]
22936 type: "MultiPolygon",
22937 coordinates: [[[[169.70504, -47.56021], [179.49541, -47.2902], [174.46634, -41.55028], [174.58663, -40.80446], [170.27492, -36.38133], [166.56976, -39.94841], [164.8365, -46.0205], [167.52103, -46.41337], [169.70504, -47.56021]]]]
22942 wikidata: "Q123076",
22943 nameEn: "Palmyra Atoll",
22944 aliases: ["UM-95"],
22946 groups: ["UM", "Q1352230", "061", "009", "UN"],
22947 level: "subterritory",
22948 roadSpeedUnit: "mph",
22949 roadHeightUnit: "ft",
22950 callingCodes: ["1"]
22953 type: "MultiPolygon",
22954 coordinates: [[[[-161.06795, 5.2462], [-161.0731, 7.1291], [-163.24478, 5.24198], [-161.06795, 5.2462]]]]
22959 wikidata: "Q130574",
22960 nameEn: "Chafarinas Islands",
22962 groups: ["EU", "Q191011", "015", "002", "UN"],
22963 level: "subterritory"
22966 type: "MultiPolygon",
22967 coordinates: [[[[-2.40316, 35.16893], [-2.43262, 35.20652], [-2.45965, 35.16527], [-2.40316, 35.16893]]]]
22972 wikidata: "Q130895",
22973 nameEn: "Kingman Reef",
22974 aliases: ["UM-89"],
22976 groups: ["UM", "Q1352230", "061", "009", "UN"],
22977 level: "subterritory",
22978 roadSpeedUnit: "mph",
22979 roadHeightUnit: "ft"
22982 type: "MultiPolygon",
22983 coordinates: [[[[-161.0731, 7.1291], [-163.16627, 7.15036], [-163.24478, 5.24198], [-161.0731, 7.1291]]]]
22988 wikidata: "Q131008",
22989 nameEn: "Johnston Atoll",
22990 aliases: ["JT", "JTN", "JTUM", "396", "UM-67"],
22992 groups: ["UM", "Q1352230", "061", "009", "UN"],
22993 level: "subterritory",
22994 roadSpeedUnit: "mph",
22995 roadHeightUnit: "ft",
22996 callingCodes: ["1"]
22999 type: "MultiPolygon",
23000 coordinates: [[[[-170.65691, 16.57199], [-168.87689, 16.01159], [-169.2329, 17.4933], [-170.65691, 16.57199]]]]
23005 wikidata: "Q131305",
23006 nameEn: "Howland Island",
23007 aliases: ["UM-84"],
23009 groups: ["UM", "Q1352230", "061", "009", "UN"],
23010 level: "subterritory",
23011 roadSpeedUnit: "mph",
23012 roadHeightUnit: "ft"
23015 type: "MultiPolygon",
23016 coordinates: [[[[-177.91421, 0.39582], [-175.31323, 0.5442], [-176.74464, 2.28109], [-177.91421, 0.39582]]]]
23021 wikidata: "Q133888",
23022 nameEn: "Ashmore and Cartier Islands",
23024 groups: ["053", "009", "UN"],
23026 callingCodes: ["61"]
23029 type: "MultiPolygon",
23030 coordinates: [[[[123.7463, -11.1783], [120.6877, -13.59408], [125.29076, -12.33139], [123.7463, -11.1783]]]]
23035 wikidata: "Q153732",
23036 nameEn: "Mariana Islands",
23037 level: "sharedLandform"
23043 wikidata: "Q172216",
23044 nameEn: "Coral Sea Islands",
23046 groups: ["053", "009", "UN"],
23048 callingCodes: ["61"]
23051 type: "MultiPolygon",
23052 coordinates: [[[[159.77159, -28.41151], [156.73836, -14.50464], [145.2855, -9.62524], [147.69992, -17.5933], [152.93188, -20.92631], [154.02855, -24.43238], [159.77159, -28.41151]]]]
23057 wikidata: "Q179313",
23058 nameEn: "Alderney",
23060 groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23061 level: "subterritory",
23063 roadSpeedUnit: "mph",
23064 roadHeightUnit: "ft",
23065 callingCodes: ["44 01481"]
23068 type: "MultiPolygon",
23069 coordinates: [[[[-2.36485, 49.48223], [-2.09454, 49.46288], [-2.02963, 49.91866], [-2.49556, 49.79012], [-2.36485, 49.48223]]]]
23074 wikidata: "Q185086",
23075 nameEn: "Crown Dependencies",
23077 level: "subcountryGroup"
23083 wikidata: "Q190571",
23084 nameEn: "Scattered Islands",
23086 groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23087 level: "subterritory"
23090 type: "MultiPolygon",
23091 coordinates: [[[[53.53458, -16.36909], [54.96649, -16.28353], [54.61476, -15.02273], [53.53458, -16.36909]]], [[[38.55969, -20.75596], [40.68027, -23.38889], [43.52893, -15.62903], [38.55969, -20.75596]]], [[[47.03092, -11.05648], [47.11593, -12.08552], [47.96702, -11.46447], [47.03092, -11.05648]]]]
23096 wikidata: "Q191011",
23097 nameEn: "Plazas de soberan\xEDa",
23104 wikidata: "Q191146",
23105 nameEn: "Pe\xF1\xF3n de V\xE9lez de la Gomera",
23107 groups: ["EU", "Q191011", "015", "002", "UN"],
23108 level: "subterritory"
23111 type: "MultiPolygon",
23112 coordinates: [[[[-4.30191, 35.17419], [-4.30112, 35.17058], [-4.29436, 35.17149], [-4.30191, 35.17419]]]]
23117 wikidata: "Q201698",
23118 nameEn: "Crozet Islands",
23120 groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23121 level: "subterritory"
23124 type: "MultiPolygon",
23125 coordinates: [[[[55.03425, -43.65017], [46.31615, -46.28749], [54.5587, -47.93013], [55.03425, -43.65017]]]]
23130 wikidata: "Q578170",
23131 nameEn: "Contiguous United States",
23132 aliases: ["CONUS"],
23134 groups: ["Q35657", "021", "003", "019", "UN"],
23135 roadSpeedUnit: "mph",
23136 roadHeightUnit: "ft",
23137 callingCodes: ["1"]
23140 type: "MultiPolygon",
23141 coordinates: [[[[-97.13927, 25.96583], [-96.92418, 25.97377], [-80.57035, 24.0565], [-78.91214, 27.76553], [-61.98255, 37.34815], [-67.16117, 44.20069], [-66.93432, 44.82597], [-66.96824, 44.83078], [-66.98249, 44.87071], [-66.96824, 44.90965], [-67.0216, 44.95333], [-67.11316, 45.11176], [-67.15965, 45.16179], [-67.19603, 45.16771], [-67.20349, 45.1722], [-67.22751, 45.16344], [-67.27039, 45.1934], [-67.29748, 45.18173], [-67.29754, 45.14865], [-67.34927, 45.122], [-67.48201, 45.27351], [-67.42394, 45.37969], [-67.50578, 45.48971], [-67.42144, 45.50584], [-67.43815, 45.59162], [-67.6049, 45.60725], [-67.80705, 45.69528], [-67.80653, 45.80022], [-67.75654, 45.82324], [-67.80961, 45.87531], [-67.75196, 45.91814], [-67.78111, 45.9392], [-67.78578, 47.06473], [-67.87993, 47.10377], [-67.94843, 47.1925], [-68.23244, 47.35712], [-68.37458, 47.35851], [-68.38332, 47.28723], [-68.57914, 47.28431], [-68.60575, 47.24659], [-68.70125, 47.24399], [-68.89222, 47.1807], [-69.05039, 47.2456], [-69.05073, 47.30076], [-69.05148, 47.42012], [-69.22119, 47.46461], [-69.99966, 46.69543], [-70.05812, 46.41768], [-70.18547, 46.35357], [-70.29078, 46.18832], [-70.23855, 46.1453], [-70.31025, 45.96424], [-70.24694, 45.95138], [-70.25976, 45.89675], [-70.41523, 45.79497], [-70.38934, 45.73215], [-70.54019, 45.67291], [-70.68516, 45.56964], [-70.72651, 45.49771], [-70.62518, 45.42286], [-70.65383, 45.37592], [-70.78372, 45.43269], [-70.82638, 45.39828], [-70.80236, 45.37444], [-70.84816, 45.22698], [-70.89864, 45.2398], [-70.91169, 45.29849], [-70.95193, 45.33895], [-71.0107, 45.34819], [-71.01866, 45.31573], [-71.08364, 45.30623], [-71.14568, 45.24128], [-71.19723, 45.25438], [-71.22338, 45.25184], [-71.29371, 45.29996], [-71.37133, 45.24624], [-71.44252, 45.2361], [-71.40364, 45.21382], [-71.42778, 45.12624], [-71.48735, 45.07784], [-71.50067, 45.01357], [-73.35025, 45.00942], [-74.32699, 44.99029], [-74.66689, 45.00646], [-74.8447, 45.00606], [-74.99101, 44.98051], [-75.01363, 44.95608], [-75.2193, 44.87821], [-75.41441, 44.76614], [-75.76813, 44.51537], [-75.8217, 44.43176], [-75.95947, 44.34463], [-76.00018, 44.34896], [-76.16285, 44.28262], [-76.1664, 44.23051], [-76.244, 44.19643], [-76.31222, 44.19894], [-76.35324, 44.13493], [-76.43859, 44.09393], [-76.79706, 43.63099], [-79.25796, 43.54052], [-79.06921, 43.26183], [-79.05512, 43.25375], [-79.05544, 43.21224], [-79.05002, 43.20133], [-79.05384, 43.17418], [-79.04652, 43.16396], [-79.0427, 43.13934], [-79.06881, 43.12029], [-79.05671, 43.10937], [-79.07486, 43.07845], [-79.01055, 43.06659], [-78.99941, 43.05612], [-79.02424, 43.01983], [-79.02074, 42.98444], [-78.98126, 42.97], [-78.96312, 42.95509], [-78.93224, 42.95229], [-78.90905, 42.93022], [-78.90712, 42.89733], [-78.93684, 42.82887], [-82.67862, 41.67615], [-83.11184, 41.95671], [-83.14962, 42.04089], [-83.12724, 42.2376], [-83.09837, 42.28877], [-83.07837, 42.30978], [-83.02253, 42.33045], [-82.82964, 42.37355], [-82.64242, 42.55594], [-82.58873, 42.54984], [-82.57583, 42.5718], [-82.51858, 42.611], [-82.51063, 42.66025], [-82.46613, 42.76615], [-82.4826, 42.8068], [-82.45331, 42.93139], [-82.4253, 42.95423], [-82.4146, 42.97626], [-82.42469, 42.992], [-82.48419, 45.30225], [-83.59589, 45.82131], [-83.43746, 45.99749], [-83.57017, 46.105], [-83.83329, 46.12169], [-83.90453, 46.05922], [-83.95399, 46.05634], [-84.1096, 46.23987], [-84.09756, 46.25512], [-84.11615, 46.2681], [-84.11254, 46.32329], [-84.13451, 46.39218], [-84.11196, 46.50248], [-84.12885, 46.53068], [-84.17723, 46.52753], [-84.1945, 46.54061], [-84.2264, 46.53337], [-84.26351, 46.49508], [-84.29893, 46.49127], [-84.34174, 46.50683], [-84.42101, 46.49853], [-84.4481, 46.48972], [-84.47607, 46.45225], [-84.55635, 46.45974], [-84.85871, 46.88881], [-88.37033, 48.30586], [-89.48837, 48.01412], [-89.57972, 48.00023], [-89.77248, 48.02607], [-89.89974, 47.98109], [-90.07418, 48.11043], [-90.56312, 48.09488], [-90.56444, 48.12184], [-90.75045, 48.09143], [-90.87588, 48.2484], [-91.08016, 48.18096], [-91.25025, 48.08522], [-91.43248, 48.04912], [-91.45829, 48.07454], [-91.58025, 48.04339], [-91.55649, 48.10611], [-91.70451, 48.11805], [-91.71231, 48.19875], [-91.86125, 48.21278], [-91.98929, 48.25409], [-92.05339, 48.35958], [-92.14732, 48.36578], [-92.202, 48.35252], [-92.26662, 48.35651], [-92.30939, 48.31251], [-92.27167, 48.25046], [-92.37185, 48.22259], [-92.48147, 48.36609], [-92.45588, 48.40624], [-92.50712, 48.44921], [-92.65606, 48.43471], [-92.71323, 48.46081], [-92.69927, 48.49573], [-92.62747, 48.50278], [-92.6342, 48.54133], [-92.7287, 48.54005], [-92.94973, 48.60866], [-93.25391, 48.64266], [-93.33946, 48.62787], [-93.3712, 48.60599], [-93.39758, 48.60364], [-93.40693, 48.60948], [-93.44472, 48.59147], [-93.47022, 48.54357], [-93.66382, 48.51845], [-93.79267, 48.51631], [-93.80939, 48.52439], [-93.80676, 48.58232], [-93.83288, 48.62745], [-93.85769, 48.63284], [-94.23215, 48.65202], [-94.25104, 48.65729], [-94.25172, 48.68404], [-94.27153, 48.70232], [-94.4174, 48.71049], [-94.44258, 48.69223], [-94.53826, 48.70216], [-94.54885, 48.71543], [-94.58903, 48.71803], [-94.69335, 48.77883], [-94.69669, 48.80918], [-94.70486, 48.82365], [-94.70087, 48.8339], [-94.687, 48.84077], [-94.75017, 49.09931], [-94.77355, 49.11998], [-94.82487, 49.29483], [-94.8159, 49.32299], [-94.85381, 49.32492], [-94.95681, 49.37035], [-94.99532, 49.36579], [-95.01419, 49.35647], [-95.05825, 49.35311], [-95.12903, 49.37056], [-95.15357, 49.384], [-95.15355, 48.9996], [-123.32163, 49.00419], [-123.0093, 48.83186], [-123.0093, 48.76586], [-123.26565, 48.6959], [-123.15614, 48.35395], [-123.50039, 48.21223], [-125.03842, 48.53282], [-133.98258, 38.06389], [-118.48109, 32.5991], [-117.1243, 32.53427], [-115.88053, 32.63624], [-114.71871, 32.71894], [-114.76736, 32.64094], [-114.80584, 32.62028], [-114.81141, 32.55543], [-114.79524, 32.55731], [-114.82011, 32.49609], [-111.07523, 31.33232], [-108.20979, 31.33316], [-108.20899, 31.78534], [-106.529, 31.784], [-106.52266, 31.77509], [-106.51251, 31.76922], [-106.50962, 31.76155], [-106.50111, 31.75714], [-106.48815, 31.74769], [-106.47298, 31.75054], [-106.46726, 31.75998], [-106.45244, 31.76523], [-106.43419, 31.75478], [-106.41773, 31.75196], [-106.38003, 31.73151], [-106.3718, 31.71165], [-106.34864, 31.69663], [-106.33419, 31.66303], [-106.30305, 31.62154], [-106.28084, 31.56173], [-106.24612, 31.54193], [-106.23711, 31.51262], [-106.20346, 31.46305], [-106.09025, 31.40569], [-106.00363, 31.39181], [-104.77674, 30.4236], [-104.5171, 29.64671], [-104.3969, 29.57105], [-104.39363, 29.55396], [-104.37752, 29.54255], [-103.15787, 28.93865], [-102.60596, 29.8192], [-101.47277, 29.7744], [-101.05686, 29.44738], [-101.01128, 29.36947], [-100.96725, 29.3477], [-100.94579, 29.34523], [-100.94056, 29.33371], [-100.87982, 29.296], [-100.79696, 29.24688], [-100.67294, 29.09744], [-100.63689, 28.90812], [-100.59809, 28.88197], [-100.52313, 28.75598], [-100.5075, 28.74066], [-100.51222, 28.70679], [-100.50029, 28.66117], [-99.55409, 27.61314], [-99.51478, 27.55836], [-99.52955, 27.49747], [-99.50208, 27.50021], [-99.48045, 27.49016], [-99.482, 27.47128], [-99.49744, 27.43746], [-99.53573, 27.30926], [-99.08477, 26.39849], [-99.03053, 26.41249], [-99.00546, 26.3925], [-98.35126, 26.15129], [-98.30491, 26.10475], [-98.27075, 26.09457], [-98.24603, 26.07191], [-97.97017, 26.05232], [-97.95155, 26.0625], [-97.66511, 26.01708], [-97.52025, 25.88518], [-97.49828, 25.89877], [-97.45669, 25.86874], [-97.42511, 25.83969], [-97.37332, 25.83854], [-97.35946, 25.92189], [-97.13927, 25.96583]]]]
23146 wikidata: "Q620634",
23147 nameEn: "Bir Tawil",
23148 groups: ["015", "002"],
23152 type: "MultiPolygon",
23153 coordinates: [[[[33.17563, 22.00405], [33.57251, 21.72406], [33.99686, 21.76784], [34.0765, 22.00501], [33.17563, 22.00405]]]]
23158 wikidata: "Q639185",
23159 nameEn: "Peros Banhos",
23161 groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23162 level: "subterritory"
23165 type: "MultiPolygon",
23166 coordinates: [[[[72.12587, -4.02588], [70.1848, -6.37445], [72.09518, -5.61768], [72.12587, -4.02588]]]]
23171 wikidata: "Q644636",
23173 level: "sharedLandform"
23179 wikidata: "Q851132",
23180 nameEn: "New Zealand Outlying Islands",
23182 level: "subcountryGroup"
23188 wikidata: "Q875134",
23189 nameEn: "European Russia",
23191 groups: ["151", "150", "UN"],
23192 callingCodes: ["7"]
23195 type: "MultiPolygon",
23196 coordinates: [[[[18.57853, 55.25302], [19.64312, 54.45423], [19.8038, 54.44203], [20.63871, 54.3706], [21.41123, 54.32395], [22.79705, 54.36264], [22.7253, 54.41732], [22.70208, 54.45312], [22.67788, 54.532], [22.71293, 54.56454], [22.68021, 54.58486], [22.7522, 54.63525], [22.74225, 54.64339], [22.75467, 54.6483], [22.73397, 54.66604], [22.73631, 54.72952], [22.87317, 54.79492], [22.85083, 54.88711], [22.76422, 54.92521], [22.68723, 54.9811], [22.65451, 54.97037], [22.60075, 55.01863], [22.58907, 55.07085], [22.47688, 55.04408], [22.31562, 55.0655], [22.14267, 55.05345], [22.11697, 55.02131], [22.06087, 55.02935], [22.02582, 55.05078], [22.03984, 55.07888], [21.99543, 55.08691], [21.96505, 55.07353], [21.85521, 55.09493], [21.64954, 55.1791], [21.55605, 55.20311], [21.51095, 55.18507], [21.46766, 55.21115], [21.38446, 55.29348], [21.35465, 55.28427], [21.26425, 55.24456], [20.95181, 55.27994], [20.60454, 55.40986], [18.57853, 55.25302]]], [[[26.32936, 60.00121], [26.90044, 59.63819], [27.85643, 59.58538], [28.04187, 59.47017], [28.19061, 59.39962], [28.21137, 59.38058], [28.20537, 59.36491], [28.19284, 59.35791], [28.14215, 59.28934], [28.00689, 59.28351], [27.90911, 59.24353], [27.87978, 59.18097], [27.80482, 59.1116], [27.74429, 58.98351], [27.36366, 58.78381], [27.55489, 58.39525], [27.48541, 58.22615], [27.62393, 58.09462], [27.67282, 57.92627], [27.81841, 57.89244], [27.78526, 57.83963], [27.56689, 57.83356], [27.50171, 57.78842], [27.52615, 57.72843], [27.3746, 57.66834], [27.40393, 57.62125], [27.31919, 57.57672], [27.34698, 57.52242], [27.56832, 57.53728], [27.52453, 57.42826], [27.86101, 57.29402], [27.66511, 56.83921], [27.86101, 56.88204], [28.04768, 56.59004], [28.13526, 56.57989], [28.10069, 56.524], [28.19057, 56.44637], [28.16599, 56.37806], [28.23716, 56.27588], [28.15217, 56.16964], [28.30571, 56.06035], [28.36888, 56.05805], [28.37987, 56.11399], [28.43068, 56.09407], [28.5529, 56.11705], [28.68337, 56.10173], [28.63668, 56.07262], [28.73418, 55.97131], [29.08299, 56.03427], [29.21717, 55.98971], [29.44692, 55.95978], [29.3604, 55.75862], [29.51283, 55.70294], [29.61446, 55.77716], [29.80672, 55.79569], [29.97975, 55.87281], [30.12136, 55.8358], [30.27776, 55.86819], [30.30987, 55.83592], [30.48257, 55.81066], [30.51346, 55.78982], [30.51037, 55.76568], [30.63344, 55.73079], [30.67464, 55.64176], [30.72957, 55.66268], [30.7845, 55.58514], [30.86003, 55.63169], [30.93419, 55.6185], [30.95204, 55.50667], [30.90123, 55.46621], [30.93144, 55.3914], [30.8257, 55.3313], [30.81946, 55.27931], [30.87944, 55.28223], [30.97369, 55.17134], [31.02071, 55.06167], [31.00972, 55.02783], [30.94243, 55.03964], [30.9081, 55.02232], [30.95754, 54.98609], [30.93144, 54.9585], [30.81759, 54.94064], [30.8264, 54.90062], [30.75165, 54.80699], [30.95479, 54.74346], [30.97127, 54.71967], [31.0262, 54.70698], [30.98226, 54.68872], [30.99187, 54.67046], [31.19339, 54.66947], [31.21399, 54.63113], [31.08543, 54.50361], [31.22945, 54.46585], [31.3177, 54.34067], [31.30791, 54.25315], [31.57002, 54.14535], [31.89599, 54.0837], [31.88744, 54.03653], [31.85019, 53.91801], [31.77028, 53.80015], [31.89137, 53.78099], [32.12621, 53.81586], [32.36663, 53.7166], [32.45717, 53.74039], [32.50112, 53.68594], [32.40499, 53.6656], [32.47777, 53.5548], [32.74968, 53.45597], [32.73257, 53.33494], [32.51725, 53.28431], [32.40773, 53.18856], [32.15368, 53.07594], [31.82373, 53.10042], [31.787, 53.18033], [31.62496, 53.22886], [31.56316, 53.19432], [31.40523, 53.21406], [31.36403, 53.13504], [31.3915, 53.09712], [31.33519, 53.08805], [31.32283, 53.04101], [31.24147, 53.031], [31.35667, 52.97854], [31.592, 52.79011], [31.57277, 52.71613], [31.50406, 52.69707], [31.63869, 52.55361], [31.56316, 52.51518], [31.61397, 52.48843], [31.62084, 52.33849], [31.57971, 52.32146], [31.70735, 52.26711], [31.6895, 52.1973], [31.77877, 52.18636], [31.7822, 52.11406], [31.81722, 52.09955], [31.85018, 52.11305], [31.96141, 52.08015], [31.92159, 52.05144], [32.08813, 52.03319], [32.23331, 52.08085], [32.2777, 52.10266], [32.34044, 52.1434], [32.33083, 52.23685], [32.38988, 52.24946], [32.3528, 52.32842], [32.54781, 52.32423], [32.69475, 52.25535], [32.85405, 52.27888], [32.89937, 52.2461], [33.18913, 52.3754], [33.51323, 52.35779], [33.48027, 52.31499], [33.55718, 52.30324], [33.78789, 52.37204], [34.05239, 52.20132], [34.11199, 52.14087], [34.09413, 52.00835], [34.41136, 51.82793], [34.42922, 51.72852], [34.07765, 51.67065], [34.17599, 51.63253], [34.30562, 51.5205], [34.22048, 51.4187], [34.33446, 51.363], [34.23009, 51.26429], [34.31661, 51.23936], [34.38802, 51.2746], [34.6613, 51.25053], [34.6874, 51.18], [34.82472, 51.17483], [34.97304, 51.2342], [35.14058, 51.23162], [35.12685, 51.16191], [35.20375, 51.04723], [35.31774, 51.08434], [35.40837, 51.04119], [35.32598, 50.94524], [35.39307, 50.92145], [35.41367, 50.80227], [35.47704, 50.77274], [35.48116, 50.66405], [35.39464, 50.64751], [35.47463, 50.49247], [35.58003, 50.45117], [35.61711, 50.35707], [35.73659, 50.35489], [35.80388, 50.41356], [35.8926, 50.43829], [36.06893, 50.45205], [36.20763, 50.3943], [36.30101, 50.29088], [36.47817, 50.31457], [36.58371, 50.28563], [36.56655, 50.2413], [36.64571, 50.218], [36.69377, 50.26982], [36.91762, 50.34963], [37.08468, 50.34935], [37.48204, 50.46079], [37.47243, 50.36277], [37.62486, 50.29966], [37.62879, 50.24481], [37.61113, 50.21976], [37.75807, 50.07896], [37.79515, 50.08425], [37.90776, 50.04194], [38.02999, 49.94482], [38.02999, 49.90592], [38.21675, 49.98104], [38.18517, 50.08161], [38.32524, 50.08866], [38.35408, 50.00664], [38.65688, 49.97176], [38.68677, 50.00904], [38.73311, 49.90238], [38.90477, 49.86787], [38.9391, 49.79524], [39.1808, 49.88911], [39.27968, 49.75976], [39.44496, 49.76067], [39.59142, 49.73758], [39.65047, 49.61761], [39.84548, 49.56064], [40.13249, 49.61672], [40.16683, 49.56865], [40.03636, 49.52321], [40.03087, 49.45452], [40.1141, 49.38798], [40.14912, 49.37681], [40.18331, 49.34996], [40.22176, 49.25683], [40.01988, 49.1761], [39.93437, 49.05709], [39.6836, 49.05121], [39.6683, 48.99454], [39.71353, 48.98959], [39.72649, 48.9754], [39.74874, 48.98675], [39.78368, 48.91596], [39.98967, 48.86901], [40.03636, 48.91957], [40.08168, 48.87443], [39.97182, 48.79398], [39.79466, 48.83739], [39.73104, 48.7325], [39.71765, 48.68673], [39.67226, 48.59368], [39.79764, 48.58668], [39.84548, 48.57821], [39.86196, 48.46633], [39.88794, 48.44226], [39.94847, 48.35055], [39.84136, 48.33321], [39.84273, 48.30947], [39.90041, 48.3049], [39.91465, 48.26743], [39.95248, 48.29972], [39.9693, 48.29904], [39.97325, 48.31399], [39.99241, 48.31768], [40.00752, 48.22445], [39.94847, 48.22811], [39.83724, 48.06501], [39.88256, 48.04482], [39.77544, 48.04206], [39.82213, 47.96396], [39.73935, 47.82876], [38.87979, 47.87719], [38.79628, 47.81109], [38.76379, 47.69346], [38.35062, 47.61631], [38.28679, 47.53552], [38.28954, 47.39255], [38.22225, 47.30788], [38.33074, 47.30508], [38.32112, 47.2585], [38.23049, 47.2324], [38.22955, 47.12069], [38.3384, 46.98085], [38.12112, 46.86078], [37.62608, 46.82615], [35.23066, 45.79231], [35.04991, 45.76827], [36.6645, 45.4514], [36.6545, 45.3417], [36.5049, 45.3136], [36.475, 45.2411], [36.4883, 45.0488], [33.5943, 44.03313], [39.81147, 43.06294], [40.0078, 43.38551], [40.00853, 43.40578], [40.01552, 43.42025], [40.01007, 43.42411], [40.03312, 43.44262], [40.04445, 43.47776], [40.10657, 43.57344], [40.65957, 43.56212], [41.64935, 43.22331], [42.40563, 43.23226], [42.66667, 43.13917], [42.75889, 43.19651], [43.03322, 43.08883], [43.0419, 43.02413], [43.81453, 42.74297], [43.73119, 42.62043], [43.95517, 42.55396], [44.54202, 42.75699], [44.70002, 42.74679], [44.80941, 42.61277], [44.88754, 42.74934], [45.15318, 42.70598], [45.36501, 42.55268], [45.78692, 42.48358], [45.61676, 42.20768], [46.42738, 41.91323], [46.5332, 41.87389], [46.58924, 41.80547], [46.75269, 41.8623], [46.8134, 41.76252], [47.00955, 41.63583], [46.99554, 41.59743], [47.03757, 41.55434], [47.10762, 41.59044], [47.34579, 41.27884], [47.49004, 41.26366], [47.54504, 41.20275], [47.62288, 41.22969], [47.75831, 41.19455], [47.87973, 41.21798], [48.07587, 41.49957], [48.22064, 41.51472], [48.2878, 41.56221], [48.40277, 41.60441], [48.42301, 41.65444], [48.55078, 41.77917], [48.5867, 41.84306], [48.80971, 41.95365], [49.2134, 44.84989], [49.88945, 46.04554], [49.32259, 46.26944], [49.16518, 46.38542], [48.54988, 46.56267], [48.51142, 46.69268], [49.01136, 46.72716], [48.52326, 47.4102], [48.45173, 47.40818], [48.15348, 47.74545], [47.64973, 47.76559], [47.41689, 47.83687], [47.38731, 47.68176], [47.12107, 47.83687], [47.11516, 48.27188], [46.49011, 48.43019], [46.78392, 48.95352], [47.00857, 49.04921], [47.04658, 49.19834], [46.78398, 49.34026], [46.9078, 49.86707], [47.18319, 49.93721], [47.34589, 50.09308], [47.30448, 50.30894], [47.58551, 50.47867], [48.10044, 50.09242], [48.24519, 49.86099], [48.42564, 49.82283], [48.68352, 49.89546], [48.90782, 50.02281], [48.57946, 50.63278], [48.86936, 50.61589], [49.12673, 50.78639], [49.41959, 50.85927], [49.39001, 51.09396], [49.76866, 51.11067], [49.97277, 51.2405], [50.26859, 51.28677], [50.59695, 51.61859], [51.26254, 51.68466], [51.301, 51.48799], [51.77431, 51.49536], [51.8246, 51.67916], [52.36119, 51.74161], [52.54329, 51.48444], [53.46165, 51.49445], [53.69299, 51.23466], [54.12248, 51.11542], [54.46331, 50.85554], [54.41894, 50.61214], [54.55797, 50.52006], [54.71476, 50.61214], [54.56685, 51.01958], [54.72067, 51.03261], [55.67774, 50.54508], [56.11398, 50.7471], [56.17906, 50.93204], [57.17302, 51.11253], [57.44221, 50.88354], [57.74986, 50.93017], [57.75578, 51.13852], [58.3208, 51.15151], [58.87974, 50.70852], [59.48928, 50.64216], [59.51886, 50.49937], [59.81172, 50.54451], [60.01288, 50.8163], [60.17262, 50.83312], [60.31914, 50.67705], [60.81833, 50.6629], [61.4431, 50.80679], [61.56889, 51.23679], [61.6813, 51.25716], [61.55114, 51.32746], [61.50677, 51.40687], [60.95655, 51.48615], [60.92401, 51.61124], [60.5424, 51.61675], [60.36787, 51.66815], [60.50986, 51.7964], [60.09867, 51.87135], [59.99809, 51.98263], [59.91279, 52.06924], [60.17253, 52.25814], [60.17516, 52.39457], [59.25033, 52.46803], [59.22409, 52.28437], [58.79644, 52.43392], [58.94336, 53.953], [59.70487, 54.14846], [59.95217, 54.85853], [57.95234, 54.39672], [57.14829, 54.84204], [57.25137, 55.26262], [58.81825, 55.03378], [59.49035, 55.60486], [59.28419, 56.15739], [57.51527, 56.08729], [57.28024, 56.87898], [58.07604, 57.08308], [58.13789, 57.68097], [58.81412, 57.71602], [58.71104, 58.07475], [59.40376, 58.45822], [59.15636, 59.14682], [58.3853, 59.487], [59.50685, 60.91162], [59.36223, 61.3882], [59.61398, 62.44915], [59.24834, 63.01859], [59.80579, 64.13948], [59.63945, 64.78384], [60.74386, 64.95767], [61.98014, 65.72191], [66.1708, 67.61252], [64.18965, 69.94255], [76.13964, 83.37843], [36.85549, 84.09565], [32.07813, 72.01005], [31.59909, 70.16571], [30.84095, 69.80584], [30.95011, 69.54699], [30.52662, 69.54699], [30.16363, 69.65244], [29.97205, 69.41623], [29.27631, 69.2811], [29.26623, 69.13794], [29.0444, 69.0119], [28.91738, 69.04774], [28.45957, 68.91417], [28.78224, 68.86696], [28.43941, 68.53366], [28.62982, 68.19816], [29.34179, 68.06655], [29.66955, 67.79872], [30.02041, 67.67523], [29.91155, 67.51507], [28.9839, 66.94139], [29.91155, 66.13863], [30.16363, 65.66935], [29.97205, 65.70256], [29.74013, 65.64025], [29.84096, 65.56945], [29.68972, 65.31803], [29.61914, 65.23791], [29.8813, 65.22101], [29.84096, 65.1109], [29.61914, 65.05993], [29.68972, 64.80789], [30.05271, 64.79072], [30.12329, 64.64862], [30.01238, 64.57513], [30.06279, 64.35782], [30.4762, 64.25728], [30.55687, 64.09036], [30.25437, 63.83364], [29.98213, 63.75795], [30.49637, 63.46666], [31.23244, 63.22239], [31.29294, 63.09035], [31.58535, 62.91642], [31.38369, 62.66284], [31.10136, 62.43042], [29.01829, 61.17448], [28.82816, 61.1233], [28.47974, 60.93365], [27.77352, 60.52722], [27.71177, 60.3893], [27.44953, 60.22766], [26.32936, 60.00121]]]]
23201 wikidata: "Q1083368",
23202 nameEn: "Mainland Finland",
23204 groups: ["EU", "154", "150", "UN"],
23205 callingCodes: ["358"]
23208 type: "MultiPolygon",
23209 coordinates: [[[[29.12697, 69.69193], [28.36883, 69.81658], [28.32849, 69.88605], [27.97558, 69.99671], [27.95542, 70.0965], [27.57226, 70.06215], [27.05802, 69.92069], [26.64461, 69.96565], [26.40261, 69.91377], [25.96904, 69.68397], [25.69679, 69.27039], [25.75729, 68.99383], [25.61613, 68.89602], [25.42455, 68.90328], [25.12206, 68.78684], [25.10189, 68.63307], [24.93048, 68.61102], [24.90023, 68.55579], [24.74898, 68.65143], [24.18432, 68.73936], [24.02299, 68.81601], [23.781, 68.84514], [23.68017, 68.70276], [23.13064, 68.64684], [22.53321, 68.74393], [22.38367, 68.71561], [22.27276, 68.89514], [21.63833, 69.27485], [21.27827, 69.31281], [21.00732, 69.22755], [20.98641, 69.18809], [21.11099, 69.10291], [21.05775, 69.0356], [20.72171, 69.11874], [20.55258, 69.06069], [20.78802, 69.03087], [20.91658, 68.96764], [20.85104, 68.93142], [20.90649, 68.89696], [21.03001, 68.88969], [22.00429, 68.50692], [22.73028, 68.40881], [23.10336, 68.26551], [23.15377, 68.14759], [23.26469, 68.15134], [23.40081, 68.05545], [23.65793, 67.9497], [23.45627, 67.85297], [23.54701, 67.59306], [23.39577, 67.46974], [23.75372, 67.43688], [23.75372, 67.29914], [23.54701, 67.25435], [23.58735, 67.20752], [23.56214, 67.17038], [23.98563, 66.84149], [23.98059, 66.79585], [23.89488, 66.772], [23.85959, 66.56434], [23.63776, 66.43568], [23.67591, 66.3862], [23.64982, 66.30603], [23.71339, 66.21299], [23.90497, 66.15802], [24.15791, 65.85385], [24.14798, 65.83466], [24.15107, 65.81427], [24.14112, 65.39731], [20.15877, 63.06556], [19.23413, 60.61414], [20.96741, 60.71528], [21.15143, 60.54555], [21.08159, 60.20167], [21.02509, 60.12142], [21.35468, 59.67511], [20.5104, 59.15546], [26.32936, 60.00121], [27.44953, 60.22766], [27.71177, 60.3893], [27.77352, 60.52722], [28.47974, 60.93365], [28.82816, 61.1233], [29.01829, 61.17448], [31.10136, 62.43042], [31.38369, 62.66284], [31.58535, 62.91642], [31.29294, 63.09035], [31.23244, 63.22239], [30.49637, 63.46666], [29.98213, 63.75795], [30.25437, 63.83364], [30.55687, 64.09036], [30.4762, 64.25728], [30.06279, 64.35782], [30.01238, 64.57513], [30.12329, 64.64862], [30.05271, 64.79072], [29.68972, 64.80789], [29.61914, 65.05993], [29.84096, 65.1109], [29.8813, 65.22101], [29.61914, 65.23791], [29.68972, 65.31803], [29.84096, 65.56945], [29.74013, 65.64025], [29.97205, 65.70256], [30.16363, 65.66935], [29.91155, 66.13863], [28.9839, 66.94139], [29.91155, 67.51507], [30.02041, 67.67523], [29.66955, 67.79872], [29.34179, 68.06655], [28.62982, 68.19816], [28.43941, 68.53366], [28.78224, 68.86696], [28.45957, 68.91417], [28.91738, 69.04774], [28.81248, 69.11997], [28.8629, 69.22395], [29.31664, 69.47994], [29.12697, 69.69193]]]]
23214 wikidata: "Q1184963",
23215 nameEn: "Alhucemas Islands",
23217 groups: ["EU", "Q191011", "015", "002", "UN"],
23218 level: "subterritory"
23221 type: "MultiPolygon",
23222 coordinates: [[[[-3.90602, 35.21494], [-3.88372, 35.20767], [-3.89343, 35.22728], [-3.90602, 35.21494]]]]
23227 wikidata: "Q1298289",
23228 nameEn: "Egmont Islands",
23230 groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23231 level: "subterritory"
23234 type: "MultiPolygon",
23235 coordinates: [[[[70.1848, -6.37445], [70.67958, -8.2663], [72.17991, -6.68509], [70.1848, -6.37445]]]]
23240 wikidata: "Q1352230",
23241 nameEn: "US Territories",
23243 level: "subcountryGroup"
23249 wikidata: "Q1451600",
23250 nameEn: "Overseas Countries and Territories of the EU",
23258 wikidata: "Q1544253",
23259 nameEn: "Great Chagos Bank",
23261 groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23262 level: "subterritory"
23265 type: "MultiPolygon",
23266 coordinates: [[[[70.1848, -6.37445], [72.17991, -6.68509], [73.20573, -5.20727], [70.1848, -6.37445]]]]
23271 wikidata: "Q1585511",
23272 nameEn: "Salomon Atoll",
23274 groups: ["IO", "BOTS", "014", "202", "002", "UN"],
23275 level: "subterritory"
23278 type: "MultiPolygon",
23279 coordinates: [[[[72.09518, -5.61768], [73.20573, -5.20727], [72.12587, -4.02588], [72.09518, -5.61768]]]]
23284 wikidata: "Q1681727",
23285 nameEn: "Saint-Paul and Amsterdam",
23287 groups: ["TF", "Q1451600", "014", "202", "002", "UN"],
23288 level: "subterritory"
23291 type: "MultiPolygon",
23292 coordinates: [[[[76.31747, -42.16264], [80.15867, -36.04977], [71.22311, -38.75287], [76.31747, -42.16264]]]]
23297 wikidata: "Q1901211",
23298 nameEn: "East Malaysia",
23300 groups: ["Q36117", "035", "142", "UN"],
23302 callingCodes: ["60"]
23305 type: "MultiPolygon",
23306 coordinates: [[[[110.90339, 7.52694], [109.82788, 2.86812], [109.62558, 1.99182], [109.53794, 1.91771], [109.57923, 1.80624], [109.66397, 1.79972], [109.66397, 1.60425], [110.35354, 0.98869], [110.49182, 0.88088], [110.62374, 0.873], [111.22979, 1.08326], [111.55434, 0.97864], [111.82846, 0.99349], [111.94553, 1.12016], [112.15679, 1.17004], [112.2127, 1.44135], [112.48648, 1.56516], [113.021, 1.57819], [113.01448, 1.42832], [113.64677, 1.23933], [114.03788, 1.44787], [114.57892, 1.5], [114.80706, 1.92351], [114.80706, 2.21665], [115.1721, 2.49671], [115.11343, 2.82879], [115.53713, 3.14776], [115.58276, 3.93499], [115.90217, 4.37708], [117.25801, 4.35108], [117.47313, 4.18857], [117.67641, 4.16535], [118.06469, 4.16638], [118.93936, 4.09009], [119.52945, 5.35672], [117.98544, 6.27477], [117.93857, 6.89845], [117.17735, 7.52841], [116.79524, 7.43869], [115.02521, 5.35005], [115.16236, 5.01011], [115.15092, 4.87604], [115.20737, 4.8256], [115.27819, 4.63661], [115.2851, 4.42295], [115.36346, 4.33563], [115.31275, 4.30806], [115.09978, 4.39123], [115.07737, 4.53418], [115.04064, 4.63706], [115.02278, 4.74137], [115.02955, 4.82087], [115.05038, 4.90275], [114.99417, 4.88201], [114.96982, 4.81146], [114.88841, 4.81905], [114.8266, 4.75062], [114.77303, 4.72871], [114.83189, 4.42387], [114.88039, 4.4257], [114.78539, 4.12205], [114.64211, 4.00694], [114.49922, 4.13108], [114.4416, 4.27588], [114.32176, 4.2552], [114.32176, 4.34942], [114.26876, 4.49878], [114.15813, 4.57], [114.07448, 4.58441], [114.10166, 4.76112], [110.90339, 7.52694]]]]
23311 wikidata: "Q1973345",
23312 nameEn: "Peninsular Malaysia",
23314 groups: ["035", "142", "UN"],
23316 callingCodes: ["60"]
23319 type: "MultiPolygon",
23320 coordinates: [[[[102.46318, 7.22462], [102.09086, 6.23546], [102.08127, 6.22679], [102.07732, 6.193], [102.09182, 6.14161], [102.01835, 6.05407], [101.99209, 6.04075], [101.97114, 6.01992], [101.9714, 6.00575], [101.94712, 5.98421], [101.92819, 5.85511], [101.91776, 5.84269], [101.89188, 5.8386], [101.80144, 5.74505], [101.75074, 5.79091], [101.69773, 5.75881], [101.58019, 5.93534], [101.25524, 5.78633], [101.25755, 5.71065], [101.14062, 5.61613], [100.98815, 5.79464], [101.02708, 5.91013], [101.087, 5.9193], [101.12388, 6.11411], [101.06165, 6.14161], [101.12618, 6.19431], [101.10313, 6.25617], [100.85884, 6.24929], [100.81045, 6.45086], [100.74822, 6.46231], [100.74361, 6.50811], [100.66986, 6.45086], [100.43027, 6.52389], [100.42351, 6.51762], [100.41791, 6.5189], [100.41152, 6.52299], [100.35413, 6.54932], [100.31929, 6.65413], [100.32607, 6.65933], [100.32671, 6.66526], [100.31884, 6.66423], [100.31618, 6.66781], [100.30828, 6.66462], [100.29651, 6.68439], [100.19511, 6.72559], [100.12, 6.42105], [100.0756, 6.4045], [99.91873, 6.50233], [99.50117, 6.44501], [99.31854, 5.99868], [99.75778, 3.86466], [103.03657, 1.30383], [103.56591, 1.19719], [103.62738, 1.35255], [103.67468, 1.43166], [103.7219, 1.46108], [103.74161, 1.4502], [103.76395, 1.45183], [103.81181, 1.47953], [103.86383, 1.46288], [103.89565, 1.42841], [103.93384, 1.42926], [104.00131, 1.42405], [104.02277, 1.4438], [104.04622, 1.44691], [104.07348, 1.43322], [104.08871, 1.42015], [104.09162, 1.39694], [104.08072, 1.35998], [104.12282, 1.27714], [104.34728, 1.33529], [104.56723, 1.44271], [105.01437, 3.24936], [102.46318, 7.22462]]]]
23325 wikidata: "Q2093907",
23326 nameEn: "Three Kings Islands",
23328 groups: ["Q851132", "053", "009", "UN"],
23332 type: "MultiPolygon",
23333 coordinates: [[[[174.17679, -32.62487], [170.93268, -32.97889], [171.97383, -34.64644], [174.17679, -32.62487]]]]
23338 wikidata: "Q2298216",
23339 nameEn: "Solander Islands",
23341 groups: ["Q851132", "053", "009", "UN"],
23345 type: "MultiPolygon",
23346 coordinates: [[[[167.39068, -46.49187], [166.5534, -46.39484], [166.84561, -46.84889], [167.39068, -46.49187]]]]
23351 wikidata: "Q2872203",
23352 nameEn: "Mainland Australia",
23354 groups: ["053", "009", "UN"],
23355 level: "subcountryGroup",
23357 callingCodes: ["61"]
23360 type: "MultiPolygon",
23361 coordinates: [[[[88.16419, -23.49578], [123.64533, -39.13605], [159.74028, -39.1978], [159.76765, -29.76946], [154.02855, -24.43238], [152.93188, -20.92631], [147.69992, -17.5933], [145.2855, -9.62524], [143.87386, -9.02382], [143.29772, -9.33993], [142.48658, -9.36754], [142.19246, -9.15378], [141.88934, -9.36111], [141.01842, -9.35091], [135.49042, -9.2276], [127.55165, -9.05052], [125.29076, -12.33139], [88.16419, -23.49578]]]]
23366 wikidata: "Q2914565",
23367 nameEn: "Autonomous Regions of Portugal",
23369 level: "subcountryGroup"
23375 wikidata: "Q2915956",
23376 nameEn: "Mainland Portugal",
23378 groups: ["Q12837", "EU", "039", "150", "UN"],
23379 level: "subcountryGroup",
23380 callingCodes: ["351"]
23383 type: "MultiPolygon",
23384 coordinates: [[[[-10.39881, 36.12218], [-7.37282, 36.96896], [-7.39769, 37.16868], [-7.41133, 37.20314], [-7.41854, 37.23813], [-7.43227, 37.25152], [-7.43974, 37.38913], [-7.46878, 37.47127], [-7.51759, 37.56119], [-7.41981, 37.75729], [-7.33441, 37.81193], [-7.27314, 37.90145], [-7.24544, 37.98884], [-7.12648, 38.00296], [-7.10366, 38.04404], [-7.05966, 38.01966], [-7.00375, 38.01914], [-6.93418, 38.21454], [-7.09389, 38.17227], [-7.15581, 38.27597], [-7.32529, 38.44336], [-7.265, 38.61674], [-7.26174, 38.72107], [-7.03848, 38.87221], [-7.051, 38.907], [-6.95211, 39.0243], [-6.97004, 39.07619], [-7.04011, 39.11919], [-7.10692, 39.10275], [-7.14929, 39.11287], [-7.12811, 39.17101], [-7.23566, 39.20132], [-7.23403, 39.27579], [-7.3149, 39.34857], [-7.2927, 39.45847], [-7.49477, 39.58794], [-7.54121, 39.66717], [-7.33507, 39.64569], [-7.24707, 39.66576], [-7.01613, 39.66877], [-6.97492, 39.81488], [-6.91463, 39.86618], [-6.86737, 40.01986], [-6.94233, 40.10716], [-7.00589, 40.12087], [-7.02544, 40.18564], [-7.00426, 40.23169], [-6.86085, 40.26776], [-6.86085, 40.2976], [-6.80218, 40.33239], [-6.78426, 40.36468], [-6.84618, 40.42177], [-6.84944, 40.46394], [-6.7973, 40.51723], [-6.80218, 40.55067], [-6.84292, 40.56801], [-6.79567, 40.65955], [-6.82826, 40.74603], [-6.82337, 40.84472], [-6.79892, 40.84842], [-6.80707, 40.88047], [-6.84292, 40.89771], [-6.8527, 40.93958], [-6.9357, 41.02888], [-6.913, 41.03922], [-6.88843, 41.03027], [-6.84781, 41.02692], [-6.80942, 41.03629], [-6.79241, 41.05397], [-6.75655, 41.10187], [-6.77319, 41.13049], [-6.69711, 41.1858], [-6.68286, 41.21641], [-6.65046, 41.24725], [-6.55937, 41.24417], [-6.38551, 41.35274], [-6.38553, 41.38655], [-6.3306, 41.37677], [-6.26777, 41.48796], [-6.19128, 41.57638], [-6.29863, 41.66432], [-6.44204, 41.68258], [-6.49907, 41.65823], [-6.54633, 41.68623], [-6.56426, 41.74219], [-6.51374, 41.8758], [-6.56752, 41.88429], [-6.5447, 41.94371], [-6.58544, 41.96674], [-6.61967, 41.94008], [-6.75004, 41.94129], [-6.76959, 41.98734], [-6.81196, 41.99097], [-6.82174, 41.94493], [-6.94396, 41.94403], [-6.95537, 41.96553], [-6.98144, 41.9728], [-7.01078, 41.94977], [-7.07596, 41.94977], [-7.08574, 41.97401], [-7.14115, 41.98855], [-7.18549, 41.97515], [-7.18677, 41.88793], [-7.32366, 41.8406], [-7.37092, 41.85031], [-7.42864, 41.80589], [-7.42854, 41.83262], [-7.44759, 41.84451], [-7.45566, 41.86488], [-7.49803, 41.87095], [-7.52737, 41.83939], [-7.62188, 41.83089], [-7.58603, 41.87944], [-7.65774, 41.88308], [-7.69848, 41.90977], [-7.84188, 41.88065], [-7.88055, 41.84571], [-7.88751, 41.92553], [-7.90707, 41.92432], [-7.92336, 41.8758], [-7.9804, 41.87337], [-8.01136, 41.83453], [-8.0961, 41.81024], [-8.16455, 41.81753], [-8.16944, 41.87944], [-8.19551, 41.87459], [-8.2185, 41.91237], [-8.16232, 41.9828], [-8.08796, 42.01398], [-8.08847, 42.05767], [-8.11729, 42.08537], [-8.18178, 42.06436], [-8.19406, 42.12141], [-8.18947, 42.13853], [-8.1986, 42.15402], [-8.22406, 42.1328], [-8.24681, 42.13993], [-8.2732, 42.12396], [-8.29809, 42.106], [-8.32161, 42.10218], [-8.33912, 42.08358], [-8.36353, 42.09065], [-8.38323, 42.07683], [-8.40143, 42.08052], [-8.42512, 42.07199], [-8.44123, 42.08218], [-8.48185, 42.0811], [-8.52837, 42.07658], [-8.5252, 42.06264], [-8.54563, 42.0537], [-8.58086, 42.05147], [-8.59493, 42.05708], [-8.63791, 42.04691], [-8.64626, 42.03668], [-8.65832, 42.02972], [-8.6681, 41.99703], [-8.69071, 41.98862], [-8.7478, 41.96282], [-8.74606, 41.9469], [-8.75712, 41.92833], [-8.81794, 41.90375], [-8.87157, 41.86488], [-11.19304, 41.83075], [-10.39881, 36.12218]]]]
23389 wikidata: "Q3311985",
23390 nameEn: "Guernsey",
23392 groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23393 level: "subterritory",
23395 roadSpeedUnit: "mph",
23396 roadHeightUnit: "ft",
23397 callingCodes: ["44 01481"]
23400 type: "MultiPolygon",
23401 coordinates: [[[[-2.49556, 49.79012], [-3.28154, 49.57329], [-2.65349, 49.15373], [-2.36485, 49.48223], [-2.49556, 49.79012]]]]
23406 wikidata: "Q3320166",
23407 nameEn: "Outermost Regions of the EU",
23415 wikidata: "Q3336843",
23416 nameEn: "Countries of the United Kingdom",
23418 level: "subcountryGroup"
23424 wikidata: "Q6736667",
23425 nameEn: "Mainland India",
23427 groups: ["034", "142", "UN"],
23429 callingCodes: ["91"]
23432 type: "MultiPolygon",
23433 coordinates: [[[[89.08044, 21.41871], [89.07114, 22.15335], [88.9367, 22.58527], [88.94614, 22.66941], [88.9151, 22.75228], [88.96713, 22.83346], [88.87063, 22.95235], [88.88327, 23.03885], [88.86377, 23.08759], [88.99148, 23.21134], [88.71133, 23.2492], [88.79254, 23.46028], [88.79351, 23.50535], [88.74841, 23.47361], [88.56507, 23.64044], [88.58087, 23.87105], [88.66189, 23.87607], [88.73743, 23.91751], [88.6976, 24.14703], [88.74841, 24.1959], [88.68801, 24.31464], [88.50934, 24.32474], [88.12296, 24.51301], [88.08786, 24.63232], [88.00683, 24.66477], [88.15515, 24.85806], [88.14004, 24.93529], [88.21832, 24.96642], [88.27325, 24.88796], [88.33917, 24.86803], [88.46277, 25.07468], [88.44766, 25.20149], [88.94067, 25.18534], [89.00463, 25.26583], [89.01105, 25.30303], [88.85278, 25.34679], [88.81296, 25.51546], [88.677, 25.46959], [88.4559, 25.59227], [88.45103, 25.66245], [88.242, 25.80811], [88.13138, 25.78773], [88.08804, 25.91334], [88.16581, 26.0238], [88.1844, 26.14417], [88.34757, 26.22216], [88.35153, 26.29123], [88.51649, 26.35923], [88.48749, 26.45855], [88.36938, 26.48683], [88.35153, 26.45241], [88.33093, 26.48929], [88.41196, 26.63837], [88.4298, 26.54489], [88.62144, 26.46783], [88.69485, 26.38353], [88.67837, 26.26291], [88.78961, 26.31093], [88.85004, 26.23211], [89.05328, 26.2469], [88.91321, 26.37984], [88.92357, 26.40711], [88.95612, 26.4564], [89.08899, 26.38845], [89.15869, 26.13708], [89.35953, 26.0077], [89.53515, 26.00382], [89.57101, 25.9682], [89.63968, 26.22595], [89.70201, 26.15138], [89.73581, 26.15818], [89.77865, 26.08387], [89.77728, 26.04254], [89.86592, 25.93115], [89.80585, 25.82489], [89.84388, 25.70042], [89.86129, 25.61714], [89.81208, 25.37244], [89.84086, 25.31854], [89.83371, 25.29548], [89.87629, 25.28337], [89.90478, 25.31038], [90.1155, 25.22686], [90.40034, 25.1534], [90.65042, 25.17788], [90.87427, 25.15799], [91.25517, 25.20677], [91.63648, 25.12846], [92.0316, 25.1834], [92.33957, 25.07593], [92.39147, 25.01471], [92.49887, 24.88796], [92.38626, 24.86055], [92.25854, 24.9191], [92.15796, 24.54435], [92.11662, 24.38997], [91.96603, 24.3799], [91.89258, 24.14674], [91.82596, 24.22345], [91.76004, 24.23848], [91.73257, 24.14703], [91.65292, 24.22095], [91.63782, 24.1132], [91.55542, 24.08687], [91.37414, 24.10693], [91.35741, 23.99072], [91.29587, 24.0041], [91.22308, 23.89616], [91.25192, 23.83463], [91.15579, 23.6599], [91.28293, 23.37538], [91.36453, 23.06612], [91.40848, 23.07117], [91.4035, 23.27522], [91.46615, 23.2328], [91.54993, 23.01051], [91.61571, 22.93929], [91.7324, 23.00043], [91.81634, 23.08001], [91.76417, 23.26619], [91.84789, 23.42235], [91.95642, 23.47361], [91.95093, 23.73284], [92.04706, 23.64229], [92.15417, 23.73409], [92.26541, 23.70392], [92.38214, 23.28705], [92.37665, 22.9435], [92.5181, 22.71441], [92.60029, 22.1522], [92.56616, 22.13554], [92.60949, 21.97638], [92.67532, 22.03547], [92.70416, 22.16017], [92.86208, 22.05456], [92.89504, 21.95143], [92.93899, 22.02656], [92.99804, 21.98964], [92.99255, 22.05965], [93.04885, 22.20595], [93.15734, 22.18687], [93.14224, 22.24535], [93.19991, 22.25425], [93.18206, 22.43716], [93.13537, 22.45873], [93.11477, 22.54374], [93.134, 22.59573], [93.09417, 22.69459], [93.134, 22.92498], [93.12988, 23.05772], [93.2878, 23.00464], [93.38478, 23.13698], [93.36862, 23.35426], [93.38781, 23.36139], [93.39981, 23.38828], [93.38805, 23.4728], [93.43475, 23.68299], [93.3908, 23.7622], [93.3908, 23.92925], [93.36059, 23.93176], [93.32351, 24.04468], [93.34735, 24.10151], [93.41415, 24.07854], [93.46633, 23.97067], [93.50616, 23.94432], [93.62871, 24.00922], [93.75952, 24.0003], [93.80279, 23.92549], [93.92089, 23.95812], [94.14081, 23.83333], [94.30215, 24.23752], [94.32362, 24.27692], [94.45279, 24.56656], [94.50729, 24.59281], [94.5526, 24.70764], [94.60204, 24.70889], [94.73937, 25.00545], [94.74212, 25.13606], [94.57458, 25.20318], [94.68032, 25.47003], [94.80117, 25.49359], [95.18556, 26.07338], [95.11428, 26.1019], [95.12801, 26.38397], [95.05798, 26.45408], [95.23513, 26.68499], [95.30339, 26.65372], [95.437, 26.7083], [95.81603, 27.01335], [95.93002, 27.04149], [96.04949, 27.19428], [96.15591, 27.24572], [96.40779, 27.29818], [96.55761, 27.29928], [96.73888, 27.36638], [96.88445, 27.25046], [96.85287, 27.2065], [96.89132, 27.17474], [97.14675, 27.09041], [97.17422, 27.14052], [96.91431, 27.45752], [96.90112, 27.62149], [97.29919, 27.92233], [97.35824, 27.87256], [97.38845, 28.01329], [97.35412, 28.06663], [97.31292, 28.06784], [97.34547, 28.21385], [97.1289, 28.3619], [96.98882, 28.32564], [96.88445, 28.39452], [96.85561, 28.4875], [96.6455, 28.61657], [96.48895, 28.42955], [96.40929, 28.51526], [96.61391, 28.72742], [96.3626, 29.10607], [96.20467, 29.02325], [96.18682, 29.11087], [96.31316, 29.18643], [96.05361, 29.38167], [95.84899, 29.31464], [95.75149, 29.32063], [95.72086, 29.20797], [95.50842, 29.13487], [95.41091, 29.13007], [95.3038, 29.13847], [95.26122, 29.07727], [95.2214, 29.10727], [95.11291, 29.09527], [95.0978, 29.14446], [94.81353, 29.17804], [94.69318, 29.31739], [94.2752, 29.11687], [94.35897, 29.01965], [93.72797, 28.68821], [93.44621, 28.67189], [93.18069, 28.50319], [93.14635, 28.37035], [92.93075, 28.25671], [92.67486, 28.15018], [92.65472, 28.07632], [92.73025, 28.05814], [92.7275, 27.98662], [92.42538, 27.80092], [92.32101, 27.79363], [92.27432, 27.89077], [91.87057, 27.7195], [91.84722, 27.76325], [91.6469, 27.76358], [91.55819, 27.6144], [91.65007, 27.48287], [92.01132, 27.47352], [92.12019, 27.27829], [92.04702, 27.26861], [92.03457, 27.07334], [92.11863, 26.893], [92.05523, 26.8692], [91.83181, 26.87318], [91.50067, 26.79223], [90.67715, 26.77215], [90.48504, 26.8594], [90.39271, 26.90704], [90.30402, 26.85098], [90.04535, 26.72422], [89.86124, 26.73307], [89.63369, 26.74402], [89.42349, 26.83727], [89.3901, 26.84225], [89.38319, 26.85963], [89.37913, 26.86224], [89.1926, 26.81329], [89.12825, 26.81661], [89.09554, 26.89089], [88.95807, 26.92668], [88.92301, 26.99286], [88.8714, 26.97488], [88.86984, 27.10937], [88.74219, 27.144], [88.91901, 27.32483], [88.82981, 27.38814], [88.77517, 27.45415], [88.88091, 27.85192], [88.83559, 28.01936], [88.63235, 28.12356], [88.54858, 28.06057], [88.25332, 27.9478], [88.1278, 27.95417], [88.13378, 27.88015], [88.1973, 27.85067], [88.19107, 27.79285], [88.04008, 27.49223], [88.07277, 27.43007], [88.01646, 27.21612], [88.01587, 27.21388], [87.9887, 27.11045], [88.11719, 26.98758], [88.13422, 26.98705], [88.12302, 26.95324], [88.19107, 26.75516], [88.1659, 26.68177], [88.16452, 26.64111], [88.09963, 26.54195], [88.09414, 26.43732], [88.00895, 26.36029], [87.90115, 26.44923], [87.89085, 26.48565], [87.84193, 26.43663], [87.7918, 26.46737], [87.76004, 26.40711], [87.67893, 26.43501], [87.66803, 26.40294], [87.59175, 26.38342], [87.55274, 26.40596], [87.51571, 26.43106], [87.46566, 26.44058], [87.37314, 26.40815], [87.34568, 26.34787], [87.26568, 26.37294], [87.26587, 26.40592], [87.24682, 26.4143], [87.18863, 26.40558], [87.14751, 26.40542], [87.09147, 26.45039], [87.0707, 26.58571], [87.04691, 26.58685], [87.01559, 26.53228], [86.95912, 26.52076], [86.94543, 26.52076], [86.82898, 26.43919], [86.76797, 26.45892], [86.74025, 26.42386], [86.69124, 26.45169], [86.62686, 26.46891], [86.61313, 26.48658], [86.57073, 26.49825], [86.54258, 26.53819], [86.49726, 26.54218], [86.31564, 26.61925], [86.26235, 26.61886], [86.22513, 26.58863], [86.13596, 26.60651], [86.02729, 26.66756], [85.8492, 26.56667], [85.85126, 26.60866], [85.83126, 26.61134], [85.76907, 26.63076], [85.72315, 26.67471], [85.73483, 26.79613], [85.66239, 26.84822], [85.61621, 26.86721], [85.59461, 26.85161], [85.5757, 26.85955], [85.56471, 26.84133], [85.47752, 26.79292], [85.34302, 26.74954], [85.21159, 26.75933], [85.18046, 26.80519], [85.19291, 26.86909], [85.15883, 26.86966], [85.02635, 26.85381], [85.05592, 26.88991], [85.00536, 26.89523], [84.97186, 26.9149], [84.96687, 26.95599], [84.85754, 26.98984], [84.82913, 27.01989], [84.793, 26.9968], [84.64496, 27.04669], [84.69166, 27.21294], [84.62161, 27.33885], [84.29315, 27.39], [84.25735, 27.44941], [84.21376, 27.45218], [84.10791, 27.52399], [84.02229, 27.43836], [83.93306, 27.44939], [83.86182, 27.4241], [83.85595, 27.35797], [83.61288, 27.47013], [83.39495, 27.4798], [83.38872, 27.39276], [83.35136, 27.33885], [83.29999, 27.32778], [83.2673, 27.36235], [83.27197, 27.38309], [83.19413, 27.45632], [82.94938, 27.46036], [82.93261, 27.50328], [82.74119, 27.49838], [82.70378, 27.72122], [82.46405, 27.6716], [82.06554, 27.92222], [81.97214, 27.93322], [81.91223, 27.84995], [81.47867, 28.08303], [81.48179, 28.12148], [81.38683, 28.17638], [81.32923, 28.13521], [81.19847, 28.36284], [81.03471, 28.40054], [80.55142, 28.69182], [80.50575, 28.6706], [80.52443, 28.54897], [80.44504, 28.63098], [80.37188, 28.63371], [80.12125, 28.82346], [80.06957, 28.82763], [80.05743, 28.91479], [80.18085, 29.13649], [80.23178, 29.11626], [80.26602, 29.13938], [80.24112, 29.21414], [80.28626, 29.20327], [80.31428, 29.30784], [80.24322, 29.44299], [80.37939, 29.57098], [80.41858, 29.63581], [80.38428, 29.68513], [80.36803, 29.73865], [80.41554, 29.79451], [80.43458, 29.80466], [80.48997, 29.79566], [80.56247, 29.86661], [80.57179, 29.91422], [80.60226, 29.95732], [80.67076, 29.95732], [80.8778, 30.13384], [80.86673, 30.17321], [80.91143, 30.22173], [80.92547, 30.17193], [81.03953, 30.20059], [80.83343, 30.32023], [80.54504, 30.44936], [80.20721, 30.58541], [79.93255, 30.88288], [79.59884, 30.93943], [79.30694, 31.17357], [79.14016, 31.43403], [79.01931, 31.42817], [78.89344, 31.30481], [78.77898, 31.31209], [78.71032, 31.50197], [78.84516, 31.60631], [78.69933, 31.78723], [78.78036, 31.99478], [78.74404, 32.00384], [78.68754, 32.10256], [78.49609, 32.2762], [78.4645, 32.45367], [78.38897, 32.53938], [78.73916, 32.69438], [78.7831, 32.46873], [78.96713, 32.33655], [78.99322, 32.37948], [79.0979, 32.38051], [79.13174, 32.47766], [79.26768, 32.53277], [79.46562, 32.69668], [79.14016, 33.02545], [79.15252, 33.17156], [78.73636, 33.56521], [78.67599, 33.66445], [78.77349, 33.73871], [78.73367, 34.01121], [78.65657, 34.03195], [78.66225, 34.08858], [78.91769, 34.15452], [78.99802, 34.3027], [79.05364, 34.32482], [78.74465, 34.45174], [78.56475, 34.50835], [78.54964, 34.57283], [78.27781, 34.61484], [78.18435, 34.7998], [78.22692, 34.88771], [78.00033, 35.23954], [78.03466, 35.3785], [78.11664, 35.48022], [77.80532, 35.52058], [77.70232, 35.46244], [77.44277, 35.46132], [76.96624, 35.5932], [76.84539, 35.67356], [76.77323, 35.66062], [76.75475, 35.52617], [76.85088, 35.39754], [76.93465, 35.39866], [77.11796, 35.05419], [76.99251, 34.93349], [76.87193, 34.96906], [76.74514, 34.92488], [76.74377, 34.84039], [76.67648, 34.76371], [76.47186, 34.78965], [76.15463, 34.6429], [76.04614, 34.67566], [75.75438, 34.51827], [75.38009, 34.55021], [75.01479, 34.64629], [74.6663, 34.703], [74.58083, 34.77386], [74.31239, 34.79626], [74.12897, 34.70073], [73.96423, 34.68244], [73.93401, 34.63386], [73.93951, 34.57169], [73.89419, 34.54568], [73.88732, 34.48911], [73.74999, 34.3781], [73.74862, 34.34183], [73.8475, 34.32935], [73.90517, 34.35317], [73.98208, 34.2522], [73.90677, 34.10504], [73.88732, 34.05105], [73.91341, 34.01235], [74.21554, 34.03853], [74.25262, 34.01577], [74.26086, 33.92237], [74.14001, 33.83002], [74.05898, 33.82089], [74.00891, 33.75437], [73.96423, 33.73071], [73.98968, 33.66155], [73.97367, 33.64061], [74.03576, 33.56718], [74.10115, 33.56392], [74.18121, 33.4745], [74.17983, 33.3679], [74.08782, 33.26232], [74.01366, 33.25199], [74.02144, 33.18908], [74.15374, 33.13477], [74.17571, 33.07495], [74.31854, 33.02891], [74.34875, 32.97823], [74.31227, 32.92795], [74.41467, 32.90563], [74.45312, 32.77755], [74.6289, 32.75561], [74.64675, 32.82604], [74.7113, 32.84219], [74.65345, 32.71225], [74.69542, 32.66792], [74.64424, 32.60985], [74.65251, 32.56416], [74.67431, 32.56676], [74.68362, 32.49298], [74.84725, 32.49075], [74.97634, 32.45367], [75.03265, 32.49538], [75.28259, 32.36556], [75.38046, 32.26836], [75.25649, 32.10187], [75.00793, 32.03786], [74.9269, 32.0658], [74.86236, 32.04485], [74.79919, 31.95983], [74.58907, 31.87824], [74.47771, 31.72227], [74.57498, 31.60382], [74.61517, 31.55698], [74.59319, 31.50197], [74.64713, 31.45605], [74.59773, 31.4136], [74.53223, 31.30321], [74.51629, 31.13829], [74.56023, 31.08303], [74.60281, 31.10419], [74.60006, 31.13711], [74.6852, 31.12771], [74.67971, 31.05479], [74.5616, 31.04153], [73.88993, 30.36305], [73.95736, 30.28466], [73.97225, 30.19829], [73.80299, 30.06969], [73.58665, 30.01848], [73.3962, 29.94707], [73.28094, 29.56646], [73.05886, 29.1878], [73.01337, 29.16422], [72.94272, 29.02487], [72.40402, 28.78283], [72.29495, 28.66367], [72.20329, 28.3869], [71.9244, 28.11555], [71.89921, 27.96035], [70.79054, 27.68423], [70.60927, 28.02178], [70.37307, 28.01208], [70.12502, 27.8057], [70.03136, 27.56627], [69.58519, 27.18109], [69.50904, 26.74892], [69.88555, 26.56836], [70.05584, 26.60398], [70.17532, 26.55362], [70.17532, 26.24118], [70.08193, 26.08094], [70.0985, 25.93238], [70.2687, 25.71156], [70.37444, 25.67443], [70.53649, 25.68928], [70.60378, 25.71898], [70.67382, 25.68186], [70.66695, 25.39314], [70.89148, 25.15064], [70.94002, 24.92843], [71.09405, 24.69017], [70.97594, 24.60904], [71.00341, 24.46038], [71.12838, 24.42662], [71.04461, 24.34657], [70.94985, 24.3791], [70.85784, 24.30903], [70.88393, 24.27398], [70.71502, 24.23517], [70.57906, 24.27774], [70.5667, 24.43787], [70.11712, 24.30915], [70.03428, 24.172], [69.73335, 24.17007], [69.59579, 24.29777], [69.29778, 24.28712], [69.19341, 24.25646], [69.07806, 24.29777], [68.97781, 24.26021], [68.90914, 24.33156], [68.7416, 24.31904], [68.74643, 23.97027], [68.39339, 23.96838], [68.20763, 23.85849], [68.11329, 23.53945], [76.59015, 5.591], [79.50447, 8.91876], [79.42124, 9.80115], [80.48418, 10.20786], [89.08044, 21.41871]]]]
23438 wikidata: "Q9143535",
23439 nameEn: "Akrotiri",
23441 groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
23442 level: "subterritory",
23444 callingCodes: ["357"]
23447 type: "MultiPolygon",
23448 coordinates: [[[[32.86014, 34.70585], [32.82717, 34.70622], [32.79433, 34.67883], [32.76136, 34.68318], [32.75515, 34.64985], [32.74412, 34.43926], [33.26744, 34.49942], [33.0138, 34.64424], [32.96968, 34.64046], [32.96718, 34.63446], [32.95891, 34.62919], [32.95323, 34.64075], [32.95471, 34.64528], [32.94976, 34.65204], [32.94796, 34.6587], [32.95325, 34.66462], [32.97079, 34.66112], [32.97736, 34.65277], [32.99014, 34.65518], [32.98668, 34.67268], [32.99135, 34.68061], [32.95539, 34.68471], [32.94683, 34.67907], [32.94379, 34.67111], [32.93693, 34.67027], [32.93449, 34.66241], [32.92807, 34.66736], [32.93043, 34.67091], [32.91398, 34.67343], [32.9068, 34.66102], [32.86167, 34.68734], [32.86014, 34.70585]]]]
23453 wikidata: "Q9206745",
23454 nameEn: "Dhekelia",
23456 groups: ["Q644636", "Q37362", "BOTS", "145", "142", "UN"],
23457 level: "subterritory",
23459 callingCodes: ["357"]
23462 type: "MultiPolygon",
23463 coordinates: [[[[33.70575, 34.97947], [33.83531, 34.73974], [33.98684, 34.76642], [33.90075, 34.96623], [33.86432, 34.97592], [33.84811, 34.97075], [33.83505, 34.98108], [33.85621, 34.98956], [33.85891, 35.001], [33.85216, 35.00579], [33.84045, 35.00616], [33.82875, 35.01685], [33.83055, 35.02865], [33.81524, 35.04192], [33.8012, 35.04786], [33.82051, 35.0667], [33.8355, 35.05777], [33.85261, 35.0574], [33.88367, 35.07877], [33.89485, 35.06873], [33.90247, 35.07686], [33.91299, 35.07579], [33.91789, 35.08688], [33.89853, 35.11377], [33.88737, 35.11408], [33.88943, 35.12007], [33.88561, 35.12449], [33.87224, 35.12293], [33.87622, 35.10457], [33.87097, 35.09389], [33.87479, 35.08881], [33.8541, 35.07201], [33.84168, 35.06823], [33.82067, 35.07826], [33.78581, 35.05104], [33.76106, 35.04253], [33.73824, 35.05321], [33.71482, 35.03722], [33.70209, 35.04882], [33.7161, 35.07279], [33.70861, 35.07644], [33.69095, 35.06237], [33.68474, 35.06602], [33.67742, 35.05963], [33.67678, 35.03866], [33.69938, 35.03123], [33.69731, 35.01754], [33.71514, 35.00294], [33.70639, 34.99303], [33.70575, 34.97947]], [[33.77312, 34.9976], [33.77553, 34.99518], [33.78516, 34.99582], [33.79191, 34.98914], [33.78917, 34.98854], [33.78571, 34.98951], [33.78318, 34.98699], [33.78149, 34.98854], [33.77843, 34.988], [33.7778, 34.98981], [33.76738, 34.99188], [33.76605, 34.99543], [33.75682, 34.99916], [33.75994, 35.00113], [33.77312, 34.9976]], [[33.74144, 35.01053], [33.7343, 35.01178], [33.73781, 35.02181], [33.74265, 35.02329], [33.74983, 35.02274], [33.7492, 35.01319], [33.74144, 35.01053]]]]
23468 wikidata: "Q16390686",
23469 nameEn: "Peninsular Spain",
23471 groups: ["Q12837", "EU", "039", "150", "UN"],
23472 callingCodes: ["34"]
23475 type: "MultiPolygon",
23476 coordinates: [[[[3.75438, 42.33445], [3.17156, 42.43545], [3.11379, 42.43646], [3.10027, 42.42621], [3.08167, 42.42748], [3.03734, 42.47363], [2.96518, 42.46692], [2.94283, 42.48174], [2.92107, 42.4573], [2.88413, 42.45938], [2.86983, 42.46843], [2.85675, 42.45444], [2.84335, 42.45724], [2.77464, 42.41046], [2.75497, 42.42578], [2.72056, 42.42298], [2.65311, 42.38771], [2.6747, 42.33974], [2.57934, 42.35808], [2.55516, 42.35351], [2.54382, 42.33406], [2.48457, 42.33933], [2.43508, 42.37568], [2.43299, 42.39423], [2.38504, 42.39977], [2.25551, 42.43757], [2.20578, 42.41633], [2.16599, 42.42314], [2.12789, 42.41291], [2.11621, 42.38393], [2.06241, 42.35906], [2.00488, 42.35399], [1.96482, 42.37787], [1.9574, 42.42401], [1.94084, 42.43039], [1.94061, 42.43333], [1.94292, 42.44316], [1.93663, 42.45439], [1.88853, 42.4501], [1.83037, 42.48395], [1.76335, 42.48863], [1.72515, 42.50338], [1.70571, 42.48867], [1.66826, 42.50779], [1.65674, 42.47125], [1.58933, 42.46275], [1.57953, 42.44957], [1.55937, 42.45808], [1.55073, 42.43299], [1.5127, 42.42959], [1.44529, 42.43724], [1.43838, 42.47848], [1.41648, 42.48315], [1.46661, 42.50949], [1.44759, 42.54431], [1.41245, 42.53539], [1.4234, 42.55959], [1.44529, 42.56722], [1.42512, 42.58292], [1.44197, 42.60217], [1.35562, 42.71944], [1.15928, 42.71407], [1.0804, 42.78569], [0.98292, 42.78754], [0.96166, 42.80629], [0.93089, 42.79154], [0.711, 42.86372], [0.66121, 42.84021], [0.65421, 42.75872], [0.67873, 42.69458], [0.40214, 42.69779], [0.36251, 42.72282], [0.29407, 42.67431], [0.25336, 42.7174], [0.17569, 42.73424], [-0.02468, 42.68513], [-0.10519, 42.72761], [-0.16141, 42.79535], [-0.17939, 42.78974], [-0.3122, 42.84788], [-0.38833, 42.80132], [-0.41319, 42.80776], [-0.44334, 42.79939], [-0.50863, 42.82713], [-0.55497, 42.77846], [-0.67637, 42.88303], [-0.69837, 42.87945], [-0.72608, 42.89318], [-0.73422, 42.91228], [-0.72037, 42.92541], [-0.75478, 42.96916], [-0.81652, 42.95166], [-0.97133, 42.96239], [-1.00963, 42.99279], [-1.10333, 43.0059], [-1.22881, 43.05534], [-1.25244, 43.04164], [-1.30531, 43.06859], [-1.30052, 43.09581], [-1.27118, 43.11961], [-1.32209, 43.1127], [-1.34419, 43.09665], [-1.35272, 43.02658], [-1.44067, 43.047], [-1.47555, 43.08372], [-1.41562, 43.12815], [-1.3758, 43.24511], [-1.40942, 43.27272], [-1.45289, 43.27049], [-1.50992, 43.29481], [-1.55963, 43.28828], [-1.57674, 43.25269], [-1.61341, 43.25269], [-1.63052, 43.28591], [-1.62481, 43.30726], [-1.69407, 43.31378], [-1.73074, 43.29481], [-1.7397, 43.32979], [-1.75079, 43.3317], [-1.75334, 43.34107], [-1.77068, 43.34396], [-1.78714, 43.35476], [-1.78332, 43.36399], [-1.79319, 43.37497], [-1.77289, 43.38957], [-1.81005, 43.59738], [-10.14298, 44.17365], [-11.19304, 41.83075], [-8.87157, 41.86488], [-8.81794, 41.90375], [-8.75712, 41.92833], [-8.74606, 41.9469], [-8.7478, 41.96282], [-8.69071, 41.98862], [-8.6681, 41.99703], [-8.65832, 42.02972], [-8.64626, 42.03668], [-8.63791, 42.04691], [-8.59493, 42.05708], [-8.58086, 42.05147], [-8.54563, 42.0537], [-8.5252, 42.06264], [-8.52837, 42.07658], [-8.48185, 42.0811], [-8.44123, 42.08218], [-8.42512, 42.07199], [-8.40143, 42.08052], [-8.38323, 42.07683], [-8.36353, 42.09065], [-8.33912, 42.08358], [-8.32161, 42.10218], [-8.29809, 42.106], [-8.2732, 42.12396], [-8.24681, 42.13993], [-8.22406, 42.1328], [-8.1986, 42.15402], [-8.18947, 42.13853], [-8.19406, 42.12141], [-8.18178, 42.06436], [-8.11729, 42.08537], [-8.08847, 42.05767], [-8.08796, 42.01398], [-8.16232, 41.9828], [-8.2185, 41.91237], [-8.19551, 41.87459], [-8.16944, 41.87944], [-8.16455, 41.81753], [-8.0961, 41.81024], [-8.01136, 41.83453], [-7.9804, 41.87337], [-7.92336, 41.8758], [-7.90707, 41.92432], [-7.88751, 41.92553], [-7.88055, 41.84571], [-7.84188, 41.88065], [-7.69848, 41.90977], [-7.65774, 41.88308], [-7.58603, 41.87944], [-7.62188, 41.83089], [-7.52737, 41.83939], [-7.49803, 41.87095], [-7.45566, 41.86488], [-7.44759, 41.84451], [-7.42854, 41.83262], [-7.42864, 41.80589], [-7.37092, 41.85031], [-7.32366, 41.8406], [-7.18677, 41.88793], [-7.18549, 41.97515], [-7.14115, 41.98855], [-7.08574, 41.97401], [-7.07596, 41.94977], [-7.01078, 41.94977], [-6.98144, 41.9728], [-6.95537, 41.96553], [-6.94396, 41.94403], [-6.82174, 41.94493], [-6.81196, 41.99097], [-6.76959, 41.98734], [-6.75004, 41.94129], [-6.61967, 41.94008], [-6.58544, 41.96674], [-6.5447, 41.94371], [-6.56752, 41.88429], [-6.51374, 41.8758], [-6.56426, 41.74219], [-6.54633, 41.68623], [-6.49907, 41.65823], [-6.44204, 41.68258], [-6.29863, 41.66432], [-6.19128, 41.57638], [-6.26777, 41.48796], [-6.3306, 41.37677], [-6.38553, 41.38655], [-6.38551, 41.35274], [-6.55937, 41.24417], [-6.65046, 41.24725], [-6.68286, 41.21641], [-6.69711, 41.1858], [-6.77319, 41.13049], [-6.75655, 41.10187], [-6.79241, 41.05397], [-6.80942, 41.03629], [-6.84781, 41.02692], [-6.88843, 41.03027], [-6.913, 41.03922], [-6.9357, 41.02888], [-6.8527, 40.93958], [-6.84292, 40.89771], [-6.80707, 40.88047], [-6.79892, 40.84842], [-6.82337, 40.84472], [-6.82826, 40.74603], [-6.79567, 40.65955], [-6.84292, 40.56801], [-6.80218, 40.55067], [-6.7973, 40.51723], [-6.84944, 40.46394], [-6.84618, 40.42177], [-6.78426, 40.36468], [-6.80218, 40.33239], [-6.86085, 40.2976], [-6.86085, 40.26776], [-7.00426, 40.23169], [-7.02544, 40.18564], [-7.00589, 40.12087], [-6.94233, 40.10716], [-6.86737, 40.01986], [-6.91463, 39.86618], [-6.97492, 39.81488], [-7.01613, 39.66877], [-7.24707, 39.66576], [-7.33507, 39.64569], [-7.54121, 39.66717], [-7.49477, 39.58794], [-7.2927, 39.45847], [-7.3149, 39.34857], [-7.23403, 39.27579], [-7.23566, 39.20132], [-7.12811, 39.17101], [-7.14929, 39.11287], [-7.10692, 39.10275], [-7.04011, 39.11919], [-6.97004, 39.07619], [-6.95211, 39.0243], [-7.051, 38.907], [-7.03848, 38.87221], [-7.26174, 38.72107], [-7.265, 38.61674], [-7.32529, 38.44336], [-7.15581, 38.27597], [-7.09389, 38.17227], [-6.93418, 38.21454], [-7.00375, 38.01914], [-7.05966, 38.01966], [-7.10366, 38.04404], [-7.12648, 38.00296], [-7.24544, 37.98884], [-7.27314, 37.90145], [-7.33441, 37.81193], [-7.41981, 37.75729], [-7.51759, 37.56119], [-7.46878, 37.47127], [-7.43974, 37.38913], [-7.43227, 37.25152], [-7.41854, 37.23813], [-7.41133, 37.20314], [-7.39769, 37.16868], [-7.37282, 36.96896], [-7.2725, 35.73269], [-5.10878, 36.05227], [-2.27707, 35.35051], [3.75438, 42.33445]], [[-5.27801, 36.14942], [-5.34064, 36.03744], [-5.40526, 36.15488], [-5.34536, 36.15501], [-5.33822, 36.15272], [-5.27801, 36.14942]]], [[[1.99838, 42.44682], [2.01564, 42.45171], [1.99216, 42.46208], [1.98579, 42.47486], [1.99766, 42.4858], [1.98916, 42.49351], [1.98022, 42.49569], [1.97697, 42.48568], [1.97227, 42.48487], [1.97003, 42.48081], [1.96215, 42.47854], [1.95606, 42.45785], [1.96125, 42.45364], [1.98378, 42.44697], [1.99838, 42.44682]]]]
23481 wikidata: "Q98059339",
23482 nameEn: "Mainland Norway",
23484 groups: ["154", "150", "UN"],
23485 callingCodes: ["47"]
23488 type: "MultiPolygon",
23489 coordinates: [[[[10.40861, 58.38489], [10.64958, 58.89391], [11.08911, 58.98745], [11.15367, 59.07862], [11.34459, 59.11672], [11.4601, 58.99022], [11.45199, 58.89604], [11.65732, 58.90177], [11.8213, 59.24985], [11.69297, 59.59442], [11.92112, 59.69531], [11.87121, 59.86039], [12.15641, 59.8926], [12.36317, 59.99259], [12.52003, 60.13846], [12.59133, 60.50559], [12.2277, 61.02442], [12.69115, 61.06584], [12.86939, 61.35427], [12.57707, 61.56547], [12.40595, 61.57226], [12.14746, 61.7147], [12.29187, 62.25699], [12.07085, 62.6297], [12.19919, 63.00104], [11.98529, 63.27487], [12.19919, 63.47935], [12.14928, 63.59373], [12.74105, 64.02171], [13.23411, 64.09087], [13.98222, 64.00953], [14.16051, 64.18725], [14.11117, 64.46674], [13.64276, 64.58402], [14.50926, 65.31786], [14.53778, 66.12399], [15.05113, 66.15572], [15.49318, 66.28509], [15.37197, 66.48217], [16.35589, 67.06419], [16.39154, 67.21653], [16.09922, 67.4364], [16.12774, 67.52106], [16.38441, 67.52923], [16.7409, 67.91037], [17.30416, 68.11591], [17.90787, 67.96537], [18.13836, 68.20874], [18.1241, 68.53721], [18.39503, 68.58672], [18.63032, 68.50849], [18.97255, 68.52416], [19.93508, 68.35911], [20.22027, 68.48759], [19.95647, 68.55546], [20.22027, 68.67246], [20.33435, 68.80174], [20.28444, 68.93283], [20.0695, 69.04469], [20.55258, 69.06069], [20.72171, 69.11874], [21.05775, 69.0356], [21.11099, 69.10291], [20.98641, 69.18809], [21.00732, 69.22755], [21.27827, 69.31281], [21.63833, 69.27485], [22.27276, 68.89514], [22.38367, 68.71561], [22.53321, 68.74393], [23.13064, 68.64684], [23.68017, 68.70276], [23.781, 68.84514], [24.02299, 68.81601], [24.18432, 68.73936], [24.74898, 68.65143], [24.90023, 68.55579], [24.93048, 68.61102], [25.10189, 68.63307], [25.12206, 68.78684], [25.42455, 68.90328], [25.61613, 68.89602], [25.75729, 68.99383], [25.69679, 69.27039], [25.96904, 69.68397], [26.40261, 69.91377], [26.64461, 69.96565], [27.05802, 69.92069], [27.57226, 70.06215], [27.95542, 70.0965], [27.97558, 69.99671], [28.32849, 69.88605], [28.36883, 69.81658], [29.12697, 69.69193], [29.31664, 69.47994], [28.8629, 69.22395], [28.81248, 69.11997], [28.91738, 69.04774], [29.0444, 69.0119], [29.26623, 69.13794], [29.27631, 69.2811], [29.97205, 69.41623], [30.16363, 69.65244], [30.52662, 69.54699], [30.95011, 69.54699], [30.84095, 69.80584], [31.59909, 70.16571], [32.07813, 72.01005], [-11.60274, 67.73467], [7.28637, 57.35913], [10.40861, 58.38489]]]]
23494 wikidata: "Q98543636",
23495 nameEn: "Mainland Ecuador",
23497 groups: ["005", "419", "019", "UN"],
23498 callingCodes: ["593"]
23501 type: "MultiPolygon",
23502 coordinates: [[[[-84.52388, -3.36941], [-80.30602, -3.39149], [-80.20647, -3.431], [-80.24123, -3.46124], [-80.24586, -3.48677], [-80.23651, -3.48652], [-80.22629, -3.501], [-80.20535, -3.51667], [-80.21642, -3.5888], [-80.19848, -3.59249], [-80.18741, -3.63994], [-80.19926, -3.68894], [-80.13232, -3.90317], [-80.46386, -4.01342], [-80.4822, -4.05477], [-80.45023, -4.20938], [-80.32114, -4.21323], [-80.46386, -4.41516], [-80.39256, -4.48269], [-80.13945, -4.29786], [-79.79722, -4.47558], [-79.59402, -4.46848], [-79.26248, -4.95167], [-79.1162, -4.97774], [-79.01659, -5.01481], [-78.85149, -4.66795], [-78.68394, -4.60754], [-78.34362, -3.38633], [-78.24589, -3.39907], [-78.22642, -3.51113], [-78.14324, -3.47653], [-78.19369, -3.36431], [-77.94147, -3.05454], [-76.6324, -2.58397], [-76.05203, -2.12179], [-75.57429, -1.55961], [-75.3872, -0.9374], [-75.22862, -0.95588], [-75.22862, -0.60048], [-75.53615, -0.19213], [-75.60169, -0.18708], [-75.61997, -0.10012], [-75.40192, -0.17196], [-75.25764, -0.11943], [-75.82927, 0.09578], [-76.23441, 0.42294], [-76.41215, 0.38228], [-76.4094, 0.24015], [-76.89177, 0.24736], [-77.52001, 0.40782], [-77.49984, 0.64476], [-77.67815, 0.73863], [-77.66416, 0.81604], [-77.68613, 0.83029], [-77.7148, 0.85003], [-77.85677, 0.80197], [-78.42749, 1.15389], [-78.87137, 1.47457], [-82.12561, 4.00341], [-84.52388, -3.36941]]]]
23510 aliases: ["Earth", "Planet"],
23528 nameEn: "North America",
23537 nameEn: "South America",
23538 level: "intermediateRegion"
23555 nameEn: "Western Africa",
23556 level: "intermediateRegion"
23563 wikidata: "Q27611",
23564 nameEn: "Central America",
23565 level: "intermediateRegion"
23572 wikidata: "Q27407",
23573 nameEn: "Eastern Africa",
23574 level: "intermediateRegion"
23581 wikidata: "Q27381",
23582 nameEn: "Northern Africa",
23590 wikidata: "Q27433",
23591 nameEn: "Middle Africa",
23592 level: "intermediateRegion"
23599 wikidata: "Q27394",
23600 nameEn: "Southern Africa",
23601 level: "intermediateRegion"
23609 nameEn: "Americas",
23617 wikidata: "Q2017699",
23618 nameEn: "Northern America",
23626 wikidata: "Q664609",
23627 nameEn: "Caribbean",
23628 level: "intermediateRegion"
23635 wikidata: "Q27231",
23636 nameEn: "Eastern Asia",
23644 wikidata: "Q771405",
23645 nameEn: "Southern Asia",
23653 wikidata: "Q11708",
23654 nameEn: "South-eastern Asia",
23662 wikidata: "Q27449",
23663 nameEn: "Southern Europe",
23671 wikidata: "Q45256",
23672 nameEn: "Australia and New Zealand",
23673 aliases: ["Australasia"],
23681 wikidata: "Q37394",
23682 nameEn: "Melanesia",
23690 wikidata: "Q3359409",
23691 nameEn: "Micronesia",
23699 wikidata: "Q35942",
23700 nameEn: "Polynesia",
23717 wikidata: "Q27275",
23718 nameEn: "Central Asia",
23726 wikidata: "Q27293",
23727 nameEn: "Western Asia",
23744 wikidata: "Q27468",
23745 nameEn: "Eastern Europe",
23753 wikidata: "Q27479",
23754 nameEn: "Northern Europe",
23762 wikidata: "Q27496",
23763 nameEn: "Western Europe",
23771 wikidata: "Q132959",
23772 nameEn: "Sub-Saharan Africa",
23780 wikidata: "Q72829598",
23781 nameEn: "Latin America and the Caribbean",
23789 wikidata: "Q3405693",
23792 groups: ["GG", "830", "Q185086", "154", "150", "UN"],
23793 level: "subterritory",
23795 roadSpeedUnit: "mph",
23796 roadHeightUnit: "ft",
23797 callingCodes: ["44 01481"]
23800 type: "MultiPolygon",
23801 coordinates: [[[[-2.36485, 49.48223], [-2.65349, 49.15373], [-2.09454, 49.46288], [-2.36485, 49.48223]]]]
23807 wikidata: "Q42314",
23808 nameEn: "Channel Islands",
23809 level: "intermediateRegion"
23817 wikidata: "Q46197",
23818 nameEn: "Ascension Island",
23819 aliases: ["SH-AC"],
23821 groups: ["SH", "BOTS", "011", "202", "002", "UN"],
23822 isoStatus: "excRes",
23824 roadSpeedUnit: "mph",
23825 roadHeightUnit: "ft",
23826 callingCodes: ["247"]
23829 type: "MultiPolygon",
23830 coordinates: [[[[-14.82771, -8.70814], [-13.33271, -8.07391], [-14.91926, -6.63386], [-14.82771, -8.70814]]]]
23840 groups: ["Q12837", "039", "150", "UN"],
23841 callingCodes: ["376"]
23844 type: "MultiPolygon",
23845 coordinates: [[[[1.72515, 42.50338], [1.73683, 42.55492], [1.7858, 42.57698], [1.72588, 42.59098], [1.73452, 42.61515], [1.68267, 42.62533], [1.6625, 42.61982], [1.63485, 42.62957], [1.60085, 42.62703], [1.55418, 42.65669], [1.50867, 42.64483], [1.48043, 42.65203], [1.46718, 42.63296], [1.47986, 42.61346], [1.44197, 42.60217], [1.42512, 42.58292], [1.44529, 42.56722], [1.4234, 42.55959], [1.41245, 42.53539], [1.44759, 42.54431], [1.46661, 42.50949], [1.41648, 42.48315], [1.43838, 42.47848], [1.44529, 42.43724], [1.5127, 42.42959], [1.55073, 42.43299], [1.55937, 42.45808], [1.57953, 42.44957], [1.58933, 42.46275], [1.65674, 42.47125], [1.66826, 42.50779], [1.70571, 42.48867], [1.72515, 42.50338]]]]
23854 nameEn: "United Arab Emirates",
23855 groups: ["145", "142", "UN"],
23856 callingCodes: ["971"]
23859 type: "MultiPolygon",
23860 coordinates: [[[[56.26534, 25.62825], [56.25341, 25.61443], [56.26636, 25.60643], [56.25365, 25.60211], [56.20473, 25.61119], [56.18363, 25.65508], [56.14826, 25.66351], [56.13579, 25.73524], [56.17416, 25.77239], [56.13963, 25.82765], [56.19334, 25.9795], [56.15498, 26.06828], [56.08666, 26.05038], [55.81777, 26.18798], [55.14145, 25.62624], [53.97892, 24.64436], [52.82259, 25.51697], [52.35509, 25.00368], [52.02277, 24.75635], [51.83108, 24.71675], [51.58834, 24.66608], [51.41644, 24.39615], [51.58871, 24.27256], [51.59617, 24.12041], [52.56622, 22.94341], [55.13599, 22.63334], [55.2137, 22.71065], [55.22634, 23.10378], [55.57358, 23.669], [55.48677, 23.94946], [55.73301, 24.05994], [55.8308, 24.01633], [56.01799, 24.07426], [55.95472, 24.2172], [55.83367, 24.20193], [55.77658, 24.23476], [55.76558, 24.23227], [55.75257, 24.23466], [55.75382, 24.2466], [55.75939, 24.26114], [55.76781, 24.26209], [55.79145, 24.27914], [55.80747, 24.31069], [55.83395, 24.32776], [55.83271, 24.41521], [55.76461, 24.5287], [55.83271, 24.68567], [55.83408, 24.77858], [55.81348, 24.80102], [55.81116, 24.9116], [55.85094, 24.96858], [55.90849, 24.96771], [55.96316, 25.00857], [56.05715, 24.95727], [56.05106, 24.87461], [55.97467, 24.89639], [55.97836, 24.87673], [56.03535, 24.81161], [56.06128, 24.74457], [56.13684, 24.73699], [56.20062, 24.78565], [56.20568, 24.85063], [56.30269, 24.88334], [56.34873, 24.93205], [56.3227, 24.97284], [56.86325, 25.03856], [56.82555, 25.7713], [56.26534, 25.62825]], [[56.26062, 25.33108], [56.3005, 25.31815], [56.3111, 25.30107], [56.35172, 25.30681], [56.34438, 25.26653], [56.27628, 25.23404], [56.24341, 25.22867], [56.20872, 25.24104], [56.20838, 25.25668], [56.24465, 25.27505], [56.25008, 25.28843], [56.23362, 25.31253], [56.26062, 25.33108]]], [[[56.28423, 25.26344], [56.29379, 25.2754], [56.28102, 25.28486], [56.2716, 25.27916], [56.27086, 25.26128], [56.28423, 25.26344]]]]
23869 nameEn: "Afghanistan",
23870 groups: ["034", "142", "UN"],
23871 callingCodes: ["93"]
23874 type: "MultiPolygon",
23875 coordinates: [[[[70.61526, 38.34774], [70.60407, 38.28046], [70.54673, 38.24541], [70.4898, 38.12546], [70.17206, 37.93276], [70.1863, 37.84296], [70.27694, 37.81258], [70.28243, 37.66706], [70.15015, 37.52519], [69.95971, 37.5659], [69.93362, 37.61378], [69.84435, 37.60616], [69.80041, 37.5746], [69.51888, 37.5844], [69.44954, 37.4869], [69.36645, 37.40462], [69.45022, 37.23315], [69.39529, 37.16752], [69.25152, 37.09426], [69.03274, 37.25174], [68.96407, 37.32603], [68.88168, 37.33368], [68.91189, 37.26704], [68.80889, 37.32494], [68.81438, 37.23862], [68.6798, 37.27906], [68.61851, 37.19815], [68.41888, 37.13906], [68.41201, 37.10402], [68.29253, 37.10621], [68.27605, 37.00977], [68.18542, 37.02074], [68.02194, 36.91923], [67.87917, 37.0591], [67.7803, 37.08978], [67.78329, 37.1834], [67.51868, 37.26102], [67.2581, 37.17216], [67.2224, 37.24545], [67.13039, 37.27168], [67.08232, 37.35469], [66.95598, 37.40162], [66.64699, 37.32958], [66.55743, 37.35409], [66.30993, 37.32409], [65.72274, 37.55438], [65.64137, 37.45061], [65.64263, 37.34388], [65.51778, 37.23881], [64.97945, 37.21913], [64.61141, 36.6351], [64.62514, 36.44311], [64.57295, 36.34362], [64.43288, 36.24401], [64.05385, 36.10433], [63.98519, 36.03773], [63.56496, 35.95106], [63.53475, 35.90881], [63.29579, 35.85985], [63.12276, 35.86208], [63.10318, 35.81782], [63.23262, 35.67487], [63.10079, 35.63024], [63.12276, 35.53196], [63.0898, 35.43131], [62.90853, 35.37086], [62.74098, 35.25432], [62.62288, 35.22067], [62.48006, 35.28796], [62.29878, 35.13312], [62.29191, 35.25964], [62.15871, 35.33278], [62.05709, 35.43803], [61.97743, 35.4604], [61.77693, 35.41341], [61.58742, 35.43803], [61.27371, 35.61482], [61.18187, 35.30249], [61.0991, 35.27845], [61.12831, 35.09938], [61.06926, 34.82139], [61.00197, 34.70631], [60.99922, 34.63064], [60.72316, 34.52857], [60.91321, 34.30411], [60.66502, 34.31539], [60.50209, 34.13992], [60.5838, 33.80793], [60.5485, 33.73422], [60.57762, 33.59772], [60.69573, 33.56054], [60.91133, 33.55596], [60.88908, 33.50219], [60.56485, 33.12944], [60.86191, 32.22565], [60.84541, 31.49561], [61.70929, 31.37391], [61.80569, 31.16167], [61.80957, 31.12576], [61.83257, 31.0452], [61.8335, 30.97669], [61.78268, 30.92724], [61.80829, 30.84224], [60.87231, 29.86514], [62.47751, 29.40782], [63.5876, 29.50456], [64.12966, 29.39157], [64.19796, 29.50407], [64.62116, 29.58903], [65.04005, 29.53957], [66.24175, 29.85181], [66.36042, 29.9583], [66.23609, 30.06321], [66.34869, 30.404], [66.28413, 30.57001], [66.39194, 30.9408], [66.42645, 30.95309], [66.58175, 30.97532], [66.68166, 31.07597], [66.72561, 31.20526], [66.83273, 31.26867], [67.04147, 31.31561], [67.03323, 31.24519], [67.29964, 31.19586], [67.78854, 31.33203], [67.7748, 31.4188], [67.62374, 31.40473], [67.58323, 31.52772], [67.72056, 31.52304], [67.86887, 31.63536], [68.00071, 31.6564], [68.1655, 31.82691], [68.25614, 31.80357], [68.27605, 31.75863], [68.44222, 31.76446], [68.57475, 31.83158], [68.6956, 31.75687], [68.79997, 31.61665], [68.91078, 31.59687], [68.95995, 31.64822], [69.00939, 31.62249], [69.11514, 31.70782], [69.20577, 31.85957], [69.3225, 31.93186], [69.27032, 32.14141], [69.27932, 32.29119], [69.23599, 32.45946], [69.2868, 32.53938], [69.38155, 32.56601], [69.44747, 32.6678], [69.43649, 32.7302], [69.38018, 32.76601], [69.47082, 32.85834], [69.5436, 32.8768], [69.49854, 32.88843], [69.49004, 33.01509], [69.57656, 33.09911], [69.71526, 33.09911], [69.79766, 33.13247], [69.85259, 33.09451], [70.02563, 33.14282], [70.07369, 33.22557], [70.13686, 33.21064], [70.32775, 33.34496], [70.17062, 33.53535], [70.20141, 33.64387], [70.14785, 33.6553], [70.14236, 33.71701], [70.00503, 33.73528], [69.85671, 33.93719], [69.87307, 33.9689], [69.90203, 34.04194], [70.54336, 33.9463], [70.88119, 33.97933], [71.07345, 34.06242], [71.06933, 34.10564], [71.09307, 34.11961], [71.09453, 34.13524], [71.13078, 34.16503], [71.12815, 34.26619], [71.17662, 34.36769], [71.02401, 34.44835], [71.0089, 34.54568], [71.11602, 34.63047], [71.08718, 34.69034], [71.28356, 34.80882], [71.29472, 34.87728], [71.50329, 34.97328], [71.49917, 35.00478], [71.55273, 35.02615], [71.52938, 35.09023], [71.67495, 35.21262], [71.5541, 35.28776], [71.54294, 35.31037], [71.65435, 35.4479], [71.49917, 35.6267], [71.55273, 35.71483], [71.37969, 35.95865], [71.19505, 36.04134], [71.60491, 36.39429], [71.80267, 36.49924], [72.18135, 36.71838], [72.6323, 36.84601], [73.82685, 36.91421], [74.04856, 36.82648], [74.43389, 37.00977], [74.53739, 36.96224], [74.56453, 37.03023], [74.49981, 37.24518], [74.80605, 37.21565], [74.88887, 37.23275], [74.8294, 37.3435], [74.68383, 37.3948], [74.56161, 37.37734], [74.41055, 37.3948], [74.23339, 37.41116], [74.20308, 37.34208], [73.8564, 37.26158], [73.82552, 37.22659], [73.64974, 37.23643], [73.61129, 37.27469], [73.76647, 37.33913], [73.77197, 37.4417], [73.29633, 37.46495], [73.06884, 37.31729], [72.79693, 37.22222], [72.66381, 37.02014], [72.54095, 37.00007], [72.31676, 36.98115], [71.83229, 36.68084], [71.67083, 36.67346], [71.57195, 36.74943], [71.51502, 36.89128], [71.48481, 36.93218], [71.46923, 36.99925], [71.45578, 37.03094], [71.43097, 37.05855], [71.44127, 37.11856], [71.4494, 37.18137], [71.4555, 37.21418], [71.47386, 37.2269], [71.48339, 37.23937], [71.4824, 37.24921], [71.48536, 37.26017], [71.50674, 37.31502], [71.49821, 37.31975], [71.4862, 37.33405], [71.47685, 37.40281], [71.49612, 37.4279], [71.5256, 37.47971], [71.50616, 37.50733], [71.49693, 37.53527], [71.5065, 37.60912], [71.51972, 37.61945], [71.54186, 37.69691], [71.55234, 37.73209], [71.53053, 37.76534], [71.54324, 37.77104], [71.55752, 37.78677], [71.59255, 37.79956], [71.58843, 37.92425], [71.51565, 37.95349], [71.32871, 37.88564], [71.296, 37.93403], [71.2809, 37.91995], [71.24969, 37.93031], [71.27278, 37.96496], [71.27622, 37.99946], [71.28922, 38.01272], [71.29878, 38.04429], [71.36444, 38.15358], [71.37803, 38.25641], [71.33869, 38.27335], [71.33114, 38.30339], [71.21291, 38.32797], [71.1451, 38.40106], [71.10957, 38.40671], [71.10592, 38.42077], [71.09542, 38.42517], [71.0556, 38.40176], [71.03545, 38.44779], [70.98693, 38.48862], [70.92728, 38.43021], [70.88719, 38.46826], [70.84376, 38.44688], [70.82538, 38.45394], [70.81697, 38.44507], [70.80521, 38.44447], [70.79766, 38.44944], [70.78702, 38.45031], [70.78581, 38.45502], [70.77132, 38.45548], [70.75455, 38.4252], [70.72485, 38.4131], [70.69807, 38.41861], [70.67438, 38.40597], [70.6761, 38.39144], [70.69189, 38.37031], [70.64966, 38.34999], [70.61526, 38.34774]]]]
23884 nameEn: "Antigua and Barbuda",
23885 groups: ["029", "003", "419", "019", "UN"],
23887 roadSpeedUnit: "mph",
23888 callingCodes: ["1 268"]
23891 type: "MultiPolygon",
23892 coordinates: [[[[-61.66959, 18.6782], [-62.58307, 16.68909], [-62.1023, 16.97277], [-61.23098, 16.62484], [-61.66959, 18.6782]]]]
23900 wikidata: "Q25228",
23901 nameEn: "Anguilla",
23903 groups: ["BOTS", "029", "003", "419", "019", "UN"],
23905 roadSpeedUnit: "mph",
23906 callingCodes: ["1 264"]
23909 type: "MultiPolygon",
23910 coordinates: [[[[-63.79029, 19.11219], [-63.35989, 18.06012], [-62.62718, 18.26185], [-63.79029, 19.11219]]]]
23920 groups: ["039", "150", "UN"],
23921 callingCodes: ["355"]
23924 type: "MultiPolygon",
23925 coordinates: [[[[20.07761, 42.55582], [20.01834, 42.54622], [20.00842, 42.5109], [19.9324, 42.51699], [19.82333, 42.46581], [19.76549, 42.50237], [19.74731, 42.57422], [19.77375, 42.58517], [19.73244, 42.66299], [19.65972, 42.62774], [19.4836, 42.40831], [19.42352, 42.36546], [19.42, 42.33019], [19.28623, 42.17745], [19.40687, 42.10024], [19.37548, 42.06835], [19.36867, 42.02564], [19.37691, 41.96977], [19.34601, 41.95675], [19.33812, 41.90669], [19.37451, 41.8842], [19.37597, 41.84849], [19.26406, 41.74971], [19.0384, 40.35325], [19.95905, 39.82857], [19.97622, 39.78684], [19.92466, 39.69533], [19.98042, 39.6504], [20.00957, 39.69227], [20.05189, 39.69112], [20.12956, 39.65805], [20.15988, 39.652], [20.22376, 39.64532], [20.22707, 39.67459], [20.27412, 39.69884], [20.31961, 39.72799], [20.29152, 39.80421], [20.30804, 39.81563], [20.38572, 39.78516], [20.41475, 39.81437], [20.41546, 39.82832], [20.31135, 39.99438], [20.37911, 39.99058], [20.42373, 40.06777], [20.48487, 40.06271], [20.51297, 40.08168], [20.55593, 40.06524], [20.61081, 40.07866], [20.62566, 40.0897], [20.67162, 40.09433], [20.71789, 40.27739], [20.78234, 40.35803], [20.7906, 40.42726], [20.83688, 40.47882], [20.94925, 40.46625], [20.96908, 40.51526], [21.03932, 40.56299], [21.05833, 40.66586], [20.98134, 40.76046], [20.95752, 40.76982], [20.98396, 40.79109], [20.97887, 40.85475], [20.97693, 40.90103], [20.94305, 40.92399], [20.83671, 40.92752], [20.81567, 40.89662], [20.73504, 40.9081], [20.71634, 40.91781], [20.65558, 41.08009], [20.63454, 41.0889], [20.59832, 41.09066], [20.58546, 41.11179], [20.59715, 41.13644], [20.51068, 41.2323], [20.49432, 41.33679], [20.52119, 41.34381], [20.55976, 41.4087], [20.51301, 41.442], [20.49039, 41.49277], [20.45331, 41.51436], [20.45809, 41.5549], [20.52103, 41.56473], [20.55508, 41.58113], [20.51769, 41.65975], [20.52937, 41.69292], [20.51301, 41.72433], [20.53405, 41.78099], [20.57144, 41.7897], [20.55976, 41.87068], [20.59524, 41.8818], [20.57946, 41.91593], [20.63069, 41.94913], [20.59434, 42.03879], [20.55633, 42.08173], [20.56955, 42.12097], [20.48857, 42.25444], [20.3819, 42.3029], [20.34479, 42.32656], [20.24399, 42.32168], [20.21797, 42.41237], [20.17127, 42.50469], [20.07761, 42.55582]]]]
23935 groups: ["145", "142", "UN"],
23936 callingCodes: ["374"]
23939 type: "MultiPolygon",
23940 coordinates: [[[[45.0133, 41.29747], [44.93493, 41.25685], [44.81437, 41.30371], [44.80053, 41.25949], [44.81749, 41.23488], [44.84358, 41.23088], [44.89911, 41.21366], [44.87887, 41.20195], [44.82084, 41.21513], [44.72814, 41.20338], [44.61462, 41.24018], [44.59322, 41.1933], [44.46791, 41.18204], [44.34417, 41.2382], [44.34337, 41.20312], [44.32139, 41.2079], [44.18148, 41.24644], [44.16591, 41.19141], [43.84835, 41.16329], [43.74717, 41.1117], [43.67712, 41.13398], [43.4717, 41.12611], [43.44984, 41.0988], [43.47319, 41.02251], [43.58683, 40.98961], [43.67712, 40.93084], [43.67712, 40.84846], [43.74872, 40.7365], [43.7425, 40.66805], [43.63664, 40.54159], [43.54791, 40.47413], [43.60862, 40.43267], [43.59928, 40.34019], [43.71136, 40.16673], [43.65221, 40.14889], [43.65688, 40.11199], [43.92307, 40.01787], [44.1057, 40.03555], [44.1778, 40.02845], [44.26973, 40.04866], [44.46635, 39.97733], [44.61845, 39.8281], [44.75779, 39.7148], [44.88354, 39.74432], [44.92869, 39.72157], [45.06604, 39.79277], [45.18554, 39.67846], [45.17464, 39.58614], [45.21784, 39.58074], [45.23535, 39.61373], [45.30385, 39.61373], [45.29606, 39.57654], [45.46992, 39.49888], [45.70547, 39.60174], [45.80804, 39.56716], [45.83, 39.46487], [45.79225, 39.3695], [45.99774, 39.28931], [46.02303, 39.09978], [46.06973, 39.0744], [46.14785, 38.84206], [46.20601, 38.85262], [46.34059, 38.92076], [46.53497, 38.86548], [46.51805, 38.94982], [46.54296, 39.07078], [46.44022, 39.19636], [46.52584, 39.18912], [46.54141, 39.15895], [46.58032, 39.21204], [46.63481, 39.23013], [46.56476, 39.24942], [46.50093, 39.33736], [46.43244, 39.35181], [46.37795, 39.42039], [46.4013, 39.45405], [46.53051, 39.47809], [46.51027, 39.52373], [46.57721, 39.54414], [46.57098, 39.56694], [46.52117, 39.58734], [46.42465, 39.57534], [46.40286, 39.63651], [46.18493, 39.60533], [45.96543, 39.78859], [45.82533, 39.82925], [45.7833, 39.9475], [45.60895, 39.97733], [45.59806, 40.0131], [45.78642, 40.03218], [45.83779, 39.98925], [45.97944, 40.181], [45.95609, 40.27846], [45.65098, 40.37696], [45.42994, 40.53804], [45.45484, 40.57707], [45.35366, 40.65979], [45.4206, 40.7424], [45.55914, 40.78366], [45.60584, 40.87436], [45.40814, 40.97904], [45.44083, 41.01663], [45.39725, 41.02603], [45.35677, 40.99784], [45.28859, 41.03757], [45.26162, 41.0228], [45.25897, 41.0027], [45.1994, 41.04518], [45.16493, 41.05068], [45.1634, 41.08082], [45.1313, 41.09369], [45.12923, 41.06059], [45.06784, 41.05379], [45.08028, 41.10917], [45.19942, 41.13299], [45.1969, 41.168], [45.11811, 41.19967], [45.05201, 41.19211], [45.02932, 41.2101], [45.05497, 41.2464], [45.0133, 41.29747]], [[45.21324, 40.9817], [45.21219, 40.99001], [45.20518, 40.99348], [45.19312, 40.98998], [45.18382, 41.0066], [45.20625, 41.01484], [45.23487, 41.00226], [45.23095, 40.97828], [45.21324, 40.9817]], [[45.00864, 41.03411], [44.9903, 41.05657], [44.96031, 41.06345], [44.95383, 41.07553], [44.97169, 41.09176], [45.00864, 41.09407], [45.03406, 41.07931], [45.04517, 41.06653], [45.03792, 41.03938], [45.00864, 41.03411]]], [[[45.50279, 40.58424], [45.56071, 40.64765], [45.51825, 40.67382], [45.47927, 40.65023], [45.50279, 40.58424]]]]
23950 groups: ["017", "202", "002", "UN"],
23951 callingCodes: ["244"]
23954 type: "MultiPolygon",
23955 coordinates: [[[[16.55507, -5.85631], [13.04371, -5.87078], [12.42245, -6.07585], [11.95767, -5.94705], [12.20376, -5.76338], [12.26557, -5.74031], [12.52318, -5.74353], [12.52301, -5.17481], [12.53599, -5.1618], [12.53586, -5.14658], [12.51589, -5.1332], [12.49815, -5.14058], [12.46297, -5.09408], [12.60251, -5.01715], [12.63465, -4.94632], [12.70868, -4.95505], [12.8733, -4.74346], [13.11195, -4.67745], [13.09648, -4.63739], [12.91489, -4.47907], [12.87096, -4.40315], [12.76844, -4.38709], [12.64835, -4.55937], [12.40964, -4.60609], [12.32324, -4.78415], [12.25587, -4.79437], [12.20901, -4.75642], [12.16068, -4.90089], [12.00924, -5.02627], [11.50888, -5.33417], [10.5065, -17.25284], [11.75063, -17.25013], [12.07076, -17.15165], [12.52111, -17.24495], [12.97145, -16.98567], [13.36212, -16.98048], [13.95896, -17.43141], [14.28743, -17.38814], [18.39229, -17.38927], [18.84226, -17.80375], [21.14283, -17.94318], [21.42741, -18.02787], [23.47474, -17.62877], [23.20038, -17.47563], [22.17217, -16.50269], [22.00323, -16.18028], [21.97988, -13.00148], [24.03339, -12.99091], [23.90937, -12.844], [24.06672, -12.29058], [23.98804, -12.13149], [24.02603, -11.15368], [24.00027, -10.89356], [23.86868, -11.02856], [23.45631, -10.946], [23.16602, -11.10577], [22.54205, -11.05784], [22.25951, -11.24911], [22.17954, -10.85884], [22.32604, -10.76291], [22.19039, -9.94628], [21.84856, -9.59871], [21.79824, -7.29628], [20.56263, -7.28566], [20.61689, -6.90876], [20.31846, -6.91953], [20.30218, -6.98955], [19.5469, -7.00195], [19.33698, -7.99743], [18.33635, -8.00126], [17.5828, -8.13784], [16.96282, -7.21787], [16.55507, -5.85631]]]]
23964 nameEn: "Antarctica",
23966 callingCodes: ["672"]
23969 type: "MultiPolygon",
23970 coordinates: [[[[180, -60], [-180, -60], [-180, -90], [180, -90], [180, -60]]]]
23979 nameEn: "Argentina",
23981 groups: ["005", "419", "019", "UN"],
23982 callingCodes: ["54"]
23985 type: "MultiPolygon",
23986 coordinates: [[[[-72.31343, -50.58411], [-72.33873, -51.59954], [-71.99889, -51.98018], [-69.97824, -52.00845], [-68.41683, -52.33516], [-68.60702, -52.65781], [-68.60733, -54.9125], [-68.01394, -54.8753], [-67.46182, -54.92205], [-67.11046, -54.94199], [-66.07313, -55.19618], [-63.67376, -55.11859], [-54.78916, -36.21945], [-57.83001, -34.69099], [-58.34425, -34.15035], [-58.44442, -33.84033], [-58.40475, -33.11777], [-58.1224, -32.98842], [-58.22362, -32.52416], [-58.10036, -32.25338], [-58.20252, -31.86966], [-58.00076, -31.65016], [-58.0023, -31.53084], [-58.07569, -31.44916], [-57.98127, -31.3872], [-57.9908, -31.34924], [-57.86729, -31.06352], [-57.89476, -30.95994], [-57.8024, -30.77193], [-57.89115, -30.49572], [-57.64859, -30.35095], [-57.61478, -30.25165], [-57.65132, -30.19229], [-57.09386, -29.74211], [-56.81251, -29.48154], [-56.62789, -29.18073], [-56.57295, -29.11357], [-56.54171, -29.11447], [-56.05265, -28.62651], [-56.00458, -28.60421], [-56.01729, -28.51223], [-55.65418, -28.18304], [-55.6262, -28.17124], [-55.33303, -27.94661], [-55.16872, -27.86224], [-55.1349, -27.89759], [-54.90805, -27.73149], [-54.90159, -27.63132], [-54.67657, -27.57214], [-54.50416, -27.48232], [-54.41888, -27.40882], [-54.19268, -27.30751], [-54.19062, -27.27639], [-54.15978, -27.2889], [-53.80144, -27.09844], [-53.73372, -26.6131], [-53.68269, -26.33359], [-53.64505, -26.28089], [-53.64186, -26.25976], [-53.64632, -26.24798], [-53.63881, -26.25075], [-53.63739, -26.2496], [-53.65237, -26.23289], [-53.65018, -26.19501], [-53.73968, -26.10012], [-53.73391, -26.07006], [-53.7264, -26.0664], [-53.73086, -26.05842], [-53.73511, -26.04211], [-53.83691, -25.94849], [-53.90831, -25.55513], [-54.52926, -25.62846], [-54.5502, -25.58915], [-54.59398, -25.59224], [-54.62063, -25.91213], [-54.60664, -25.9691], [-54.67359, -25.98607], [-54.69333, -26.37705], [-54.70732, -26.45099], [-54.80868, -26.55669], [-55.00584, -26.78754], [-55.06351, -26.80195], [-55.16948, -26.96068], [-55.25243, -26.93808], [-55.39611, -26.97679], [-55.62322, -27.1941], [-55.59094, -27.32444], [-55.74475, -27.44485], [-55.89195, -27.3467], [-56.18313, -27.29851], [-56.85337, -27.5165], [-58.04205, -27.2387], [-58.59549, -27.29973], [-58.65321, -27.14028], [-58.3198, -26.83443], [-58.1188, -26.16704], [-57.87176, -25.93604], [-57.57431, -25.47269], [-57.80821, -25.13863], [-58.25492, -24.92528], [-58.33055, -24.97099], [-59.33886, -24.49935], [-59.45482, -24.34787], [-60.03367, -24.00701], [-60.28163, -24.04436], [-60.99754, -23.80934], [-61.0782, -23.62932], [-61.9756, -23.0507], [-62.22768, -22.55807], [-62.51761, -22.37684], [-62.64455, -22.25091], [-62.8078, -22.12534], [-62.81124, -21.9987], [-63.66482, -21.99918], [-63.68113, -22.0544], [-63.70963, -21.99934], [-63.93287, -21.99934], [-64.22918, -22.55807], [-64.31489, -22.88824], [-64.35108, -22.73282], [-64.4176, -22.67692], [-64.58888, -22.25035], [-64.67174, -22.18957], [-64.90014, -22.12136], [-64.99524, -22.08255], [-65.47435, -22.08908], [-65.57743, -22.07675], [-65.58694, -22.09794], [-65.61166, -22.09504], [-65.7467, -22.10105], [-65.9261, -21.93335], [-66.04832, -21.9187], [-66.03836, -21.84829], [-66.24077, -21.77837], [-66.29714, -22.08741], [-66.7298, -22.23644], [-67.18382, -22.81525], [-66.99632, -22.99839], [-67.33563, -24.04237], [-68.24825, -24.42596], [-68.56909, -24.69831], [-68.38372, -25.08636], [-68.57622, -25.32505], [-68.38372, -26.15353], [-68.56909, -26.28146], [-68.59048, -26.49861], [-68.27677, -26.90626], [-68.43363, -27.08414], [-68.77586, -27.16029], [-69.22504, -27.95042], [-69.66709, -28.44055], [-69.80969, -29.07185], [-69.99507, -29.28351], [-69.8596, -30.26131], [-70.14479, -30.36595], [-70.55832, -31.51559], [-69.88099, -33.34489], [-69.87386, -34.13344], [-70.49416, -35.24145], [-70.38008, -36.02375], [-70.95047, -36.4321], [-71.24279, -37.20264], [-70.89532, -38.6923], [-71.37826, -38.91474], [-71.92726, -40.72714], [-71.74901, -42.11711], [-72.15541, -42.15941], [-72.14828, -42.85321], [-71.64206, -43.64774], [-71.81318, -44.38097], [-71.16436, -44.46244], [-71.26418, -44.75684], [-72.06985, -44.81756], [-71.35687, -45.22075], [-71.75614, -45.61611], [-71.68577, -46.55385], [-71.94152, -47.13595], [-72.50478, -47.80586], [-72.27662, -48.28727], [-72.54042, -48.52392], [-72.56894, -48.81116], [-73.09655, -49.14342], [-73.45156, -49.79461], [-73.55259, -49.92488], [-73.15765, -50.78337], [-72.31343, -50.58411]]]]
23994 wikidata: "Q16641",
23995 nameEn: "American Samoa",
23996 aliases: ["US-AS"],
23998 groups: ["Q1352230", "061", "009", "UN"],
23999 roadSpeedUnit: "mph",
24000 roadHeightUnit: "ft",
24001 callingCodes: ["1 684"]
24004 type: "MultiPolygon",
24005 coordinates: [[[[-171.39864, -10.21587], [-170.99605, -15.1275], [-166.32598, -15.26169], [-171.39864, -10.21587]]]]
24015 groups: ["EU", "155", "150", "UN"],
24016 callingCodes: ["43"]
24019 type: "MultiPolygon",
24020 coordinates: [[[[15.34823, 48.98444], [15.28305, 48.98831], [15.26177, 48.95766], [15.16358, 48.94278], [15.15534, 48.99056], [14.99878, 49.01444], [14.97612, 48.96983], [14.98917, 48.90082], [14.95072, 48.79101], [14.98032, 48.77959], [14.9782, 48.7766], [14.98112, 48.77524], [14.9758, 48.76857], [14.95641, 48.75915], [14.94773, 48.76268], [14.81545, 48.7874], [14.80821, 48.77711], [14.80584, 48.73489], [14.72756, 48.69502], [14.71794, 48.59794], [14.66762, 48.58215], [14.60808, 48.62881], [14.56139, 48.60429], [14.4587, 48.64695], [14.43076, 48.58855], [14.33909, 48.55852], [14.20691, 48.5898], [14.09104, 48.5943], [14.01482, 48.63788], [14.06151, 48.66873], [13.84023, 48.76988], [13.82266, 48.75544], [13.81863, 48.73257], [13.79337, 48.71375], [13.81791, 48.69832], [13.81283, 48.68426], [13.81901, 48.6761], [13.82609, 48.62345], [13.80038, 48.59487], [13.80519, 48.58026], [13.76921, 48.55324], [13.7513, 48.5624], [13.74816, 48.53058], [13.72802, 48.51208], [13.66113, 48.53558], [13.65186, 48.55092], [13.62508, 48.55501], [13.59705, 48.57013], [13.57535, 48.55912], [13.51291, 48.59023], [13.50131, 48.58091], [13.50663, 48.57506], [13.46967, 48.55157], [13.45214, 48.56472], [13.43695, 48.55776], [13.45727, 48.51092], [13.42527, 48.45711], [13.43929, 48.43386], [13.40709, 48.37292], [13.30897, 48.31575], [13.26039, 48.29422], [13.18093, 48.29577], [13.126, 48.27867], [13.0851, 48.27711], [13.02083, 48.25689], [12.95306, 48.20629], [12.87126, 48.20318], [12.84475, 48.16556], [12.836, 48.1647], [12.8362, 48.15876], [12.82673, 48.15245], [12.80676, 48.14979], [12.78595, 48.12445], [12.7617, 48.12796], [12.74973, 48.10885], [12.76141, 48.07373], [12.8549, 48.01122], [12.87476, 47.96195], [12.91683, 47.95647], [12.9211, 47.95135], [12.91985, 47.94069], [12.92668, 47.93879], [12.93419, 47.94063], [12.93642, 47.94436], [12.93886, 47.94046], [12.94163, 47.92927], [13.00588, 47.84374], [12.98543, 47.82896], [12.96311, 47.79957], [12.93202, 47.77302], [12.94371, 47.76281], [12.9353, 47.74788], [12.91711, 47.74026], [12.90274, 47.72513], [12.91333, 47.7178], [12.92969, 47.71094], [12.98578, 47.7078], [13.01382, 47.72116], [13.07692, 47.68814], [13.09562, 47.63304], [13.06407, 47.60075], [13.06641, 47.58577], [13.04537, 47.58183], [13.05355, 47.56291], [13.03252, 47.53373], [13.04537, 47.49426], [12.9998, 47.46267], [12.98344, 47.48716], [12.9624, 47.47452], [12.85256, 47.52741], [12.84672, 47.54556], [12.80699, 47.54477], [12.77427, 47.58025], [12.82101, 47.61493], [12.76492, 47.64485], [12.77777, 47.66689], [12.7357, 47.6787], [12.6071, 47.6741], [12.57438, 47.63238], [12.53816, 47.63553], [12.50076, 47.62293], [12.44117, 47.6741], [12.43883, 47.6977], [12.37222, 47.68433], [12.336, 47.69534], [12.27991, 47.68827], [12.26004, 47.67725], [12.24017, 47.69534], [12.26238, 47.73544], [12.2542, 47.7433], [12.22571, 47.71776], [12.18303, 47.70065], [12.16217, 47.70105], [12.16769, 47.68167], [12.18347, 47.66663], [12.18507, 47.65984], [12.19895, 47.64085], [12.20801, 47.61082], [12.20398, 47.60667], [12.18568, 47.6049], [12.17737, 47.60121], [12.18145, 47.61019], [12.17824, 47.61506], [12.13734, 47.60639], [12.05788, 47.61742], [12.02282, 47.61033], [12.0088, 47.62451], [11.85572, 47.60166], [11.84052, 47.58354], [11.63934, 47.59202], [11.60681, 47.57881], [11.58811, 47.55515], [11.58578, 47.52281], [11.52618, 47.50939], [11.4362, 47.51413], [11.38128, 47.47465], [11.4175, 47.44621], [11.33804, 47.44937], [11.29597, 47.42566], [11.27844, 47.39956], [11.22002, 47.3964], [11.25157, 47.43277], [11.20482, 47.43198], [11.12536, 47.41222], [11.11835, 47.39719], [10.97111, 47.39561], [10.97111, 47.41617], [10.98513, 47.42882], [10.92437, 47.46991], [10.93839, 47.48018], [10.90918, 47.48571], [10.87061, 47.4786], [10.86945, 47.5015], [10.91268, 47.51334], [10.88814, 47.53701], [10.77596, 47.51729], [10.7596, 47.53228], [10.6965, 47.54253], [10.68832, 47.55752], [10.63456, 47.5591], [10.60337, 47.56755], [10.56912, 47.53584], [10.48849, 47.54057], [10.47329, 47.58552], [10.43473, 47.58394], [10.44992, 47.5524], [10.4324, 47.50111], [10.44291, 47.48453], [10.46278, 47.47901], [10.47446, 47.43318], [10.4359, 47.41183], [10.4324, 47.38494], [10.39851, 47.37623], [10.33424, 47.30813], [10.23257, 47.27088], [10.17531, 47.27167], [10.17648, 47.29149], [10.2147, 47.31014], [10.19998, 47.32832], [10.23757, 47.37609], [10.22774, 47.38904], [10.2127, 47.38019], [10.17648, 47.38889], [10.16362, 47.36674], [10.11805, 47.37228], [10.09819, 47.35724], [10.06897, 47.40709], [10.1052, 47.4316], [10.09001, 47.46005], [10.07131, 47.45531], [10.03859, 47.48927], [10.00003, 47.48216], [9.96029, 47.53899], [9.92407, 47.53111], [9.87733, 47.54688], [9.87499, 47.52953], [9.8189, 47.54688], [9.82591, 47.58158], [9.80254, 47.59419], [9.76748, 47.5934], [9.72736, 47.53457], [9.55125, 47.53629], [9.56312, 47.49495], [9.58208, 47.48344], [9.59482, 47.46305], [9.60205, 47.46165], [9.60484, 47.46358], [9.60841, 47.47178], [9.62158, 47.45858], [9.62475, 47.45685], [9.6423, 47.45599], [9.65728, 47.45383], [9.65863, 47.44847], [9.64483, 47.43842], [9.6446, 47.43233], [9.65043, 47.41937], [9.65136, 47.40504], [9.6629, 47.39591], [9.67334, 47.39191], [9.67445, 47.38429], [9.6711, 47.37824], [9.66243, 47.37136], [9.65427, 47.36824], [9.62476, 47.36639], [9.59978, 47.34671], [9.58513, 47.31334], [9.55857, 47.29919], [9.54773, 47.2809], [9.53116, 47.27029], [9.56766, 47.24281], [9.55176, 47.22585], [9.56981, 47.21926], [9.58264, 47.20673], [9.56539, 47.17124], [9.62623, 47.14685], [9.63395, 47.08443], [9.61216, 47.07732], [9.60717, 47.06091], [9.87935, 47.01337], [9.88266, 46.93343], [9.98058, 46.91434], [10.10715, 46.84296], [10.22675, 46.86942], [10.24128, 46.93147], [10.30031, 46.92093], [10.36933, 47.00212], [10.48376, 46.93891], [10.47197, 46.85698], [10.54783, 46.84505], [10.66405, 46.87614], [10.75753, 46.82258], [10.72974, 46.78972], [11.00764, 46.76896], [11.10618, 46.92966], [11.33355, 46.99862], [11.50739, 47.00644], [11.74789, 46.98484], [12.19254, 47.09331], [12.21781, 47.03996], [12.11675, 47.01241], [12.2006, 46.88854], [12.27591, 46.88651], [12.38708, 46.71529], [12.59992, 46.6595], [12.94445, 46.60401], [13.27627, 46.56059], [13.64088, 46.53438], [13.7148, 46.5222], [13.89837, 46.52331], [14.00422, 46.48474], [14.04002, 46.49117], [14.12097, 46.47724], [14.15989, 46.43327], [14.28326, 46.44315], [14.314, 46.43327], [14.42608, 46.44614], [14.45877, 46.41717], [14.52176, 46.42617], [14.56463, 46.37208], [14.5942, 46.43434], [14.66892, 46.44936], [14.72185, 46.49974], [14.81836, 46.51046], [14.83549, 46.56614], [14.86419, 46.59411], [14.87129, 46.61], [14.92283, 46.60848], [14.96002, 46.63459], [14.98024, 46.6009], [15.01451, 46.641], [15.14215, 46.66131], [15.23711, 46.63994], [15.41235, 46.65556], [15.45514, 46.63697], [15.46906, 46.61321], [15.54431, 46.6312], [15.55333, 46.64988], [15.54533, 46.66985], [15.59826, 46.68908], [15.62317, 46.67947], [15.63255, 46.68069], [15.6365, 46.6894], [15.6543, 46.69228], [15.6543, 46.70616], [15.67411, 46.70735], [15.69523, 46.69823], [15.72279, 46.69548], [15.73823, 46.70011], [15.76771, 46.69863], [15.78518, 46.70712], [15.8162, 46.71897], [15.87691, 46.7211], [15.94864, 46.68769], [15.98512, 46.68463], [15.99988, 46.67947], [16.04036, 46.6549], [16.04347, 46.68694], [16.02808, 46.71094], [15.99769, 46.7266], [15.98432, 46.74991], [15.99126, 46.78199], [15.99054, 46.82772], [16.05786, 46.83927], [16.10983, 46.867], [16.19904, 46.94134], [16.22403, 46.939], [16.27594, 46.9643], [16.28202, 47.00159], [16.51369, 47.00084], [16.43936, 47.03548], [16.52176, 47.05747], [16.46134, 47.09395], [16.52863, 47.13974], [16.44932, 47.14418], [16.46442, 47.16845], [16.4523, 47.18812], [16.42801, 47.18422], [16.41739, 47.20649], [16.43663, 47.21127], [16.44142, 47.25079], [16.47782, 47.25918], [16.45104, 47.41181], [16.49908, 47.39416], [16.52414, 47.41007], [16.57152, 47.40868], [16.6718, 47.46139], [16.64821, 47.50155], [16.71059, 47.52692], [16.64193, 47.63114], [16.58699, 47.61772], [16.4222, 47.66537], [16.55129, 47.72268], [16.53514, 47.73837], [16.54779, 47.75074], [16.61183, 47.76171], [16.65679, 47.74197], [16.72089, 47.73469], [16.7511, 47.67878], [16.82938, 47.68432], [16.86509, 47.72268], [16.87538, 47.68895], [17.08893, 47.70928], [17.05048, 47.79377], [17.07039, 47.81129], [17.00997, 47.86245], [17.08275, 47.87719], [17.11022, 47.92461], [17.09786, 47.97336], [17.16001, 48.00636], [17.07039, 48.0317], [17.09168, 48.09366], [17.05735, 48.14179], [17.02919, 48.13996], [16.97701, 48.17385], [16.89461, 48.31332], [16.90903, 48.32519], [16.84243, 48.35258], [16.83317, 48.38138], [16.83588, 48.3844], [16.8497, 48.38321], [16.85204, 48.44968], [16.94611, 48.53614], [16.93955, 48.60371], [16.90354, 48.71541], [16.79779, 48.70998], [16.71883, 48.73806], [16.68518, 48.7281], [16.67008, 48.77699], [16.46134, 48.80865], [16.40915, 48.74576], [16.37345, 48.729], [16.06034, 48.75436], [15.84404, 48.86921], [15.78087, 48.87644], [15.75341, 48.8516], [15.6921, 48.85973], [15.61622, 48.89541], [15.51357, 48.91549], [15.48027, 48.94481], [15.34823, 48.98444]]]]
24029 nameEn: "Australia"
24038 wikidata: "Q21203",
24040 aliases: ["NL-AW"],
24042 groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24043 callingCodes: ["297"]
24046 type: "MultiPolygon",
24047 coordinates: [[[[-70.00823, 12.98375], [-70.35625, 12.58277], [-69.60231, 12.17], [-70.00823, 12.98375]]]]
24056 nameEn: "\xC5land Islands",
24058 groups: ["EU", "154", "150", "UN"],
24059 callingCodes: ["358 18", "358 457"]
24062 type: "MultiPolygon",
24063 coordinates: [[[[19.08191, 60.19152], [20.5104, 59.15546], [21.35468, 59.67511], [21.02509, 60.12142], [21.08159, 60.20167], [21.15143, 60.54555], [20.96741, 60.71528], [19.23413, 60.61414], [19.08191, 60.19152]]]]
24072 nameEn: "Azerbaijan",
24073 groups: ["145", "142", "UN"],
24074 callingCodes: ["994"]
24077 type: "MultiPolygon",
24078 coordinates: [[[[46.42738, 41.91323], [46.3984, 41.84399], [46.30863, 41.79133], [46.23962, 41.75811], [46.20538, 41.77205], [46.17891, 41.72094], [46.19759, 41.62327], [46.24429, 41.59883], [46.26531, 41.63339], [46.28182, 41.60089], [46.3253, 41.60912], [46.34039, 41.5947], [46.34126, 41.57454], [46.29794, 41.5724], [46.33925, 41.4963], [46.40307, 41.48464], [46.4669, 41.43331], [46.63658, 41.37727], [46.72375, 41.28609], [46.66148, 41.20533], [46.63969, 41.09515], [46.55096, 41.1104], [46.48558, 41.0576], [46.456, 41.09984], [46.37661, 41.10805], [46.27698, 41.19011], [46.13221, 41.19479], [45.95786, 41.17956], [45.80842, 41.2229], [45.69946, 41.29545], [45.75705, 41.35157], [45.71035, 41.36208], [45.68389, 41.3539], [45.45973, 41.45898], [45.4006, 41.42402], [45.31352, 41.47168], [45.26285, 41.46433], [45.1797, 41.42231], [45.09867, 41.34065], [45.0133, 41.29747], [45.05497, 41.2464], [45.02932, 41.2101], [45.05201, 41.19211], [45.11811, 41.19967], [45.1969, 41.168], [45.19942, 41.13299], [45.08028, 41.10917], [45.06784, 41.05379], [45.12923, 41.06059], [45.1313, 41.09369], [45.1634, 41.08082], [45.16493, 41.05068], [45.1994, 41.04518], [45.25897, 41.0027], [45.26162, 41.0228], [45.28859, 41.03757], [45.35677, 40.99784], [45.39725, 41.02603], [45.44083, 41.01663], [45.40814, 40.97904], [45.60584, 40.87436], [45.55914, 40.78366], [45.4206, 40.7424], [45.35366, 40.65979], [45.45484, 40.57707], [45.42994, 40.53804], [45.65098, 40.37696], [45.95609, 40.27846], [45.97944, 40.181], [45.83779, 39.98925], [45.78642, 40.03218], [45.59806, 40.0131], [45.60895, 39.97733], [45.7833, 39.9475], [45.82533, 39.82925], [45.96543, 39.78859], [46.18493, 39.60533], [46.40286, 39.63651], [46.42465, 39.57534], [46.52117, 39.58734], [46.57098, 39.56694], [46.57721, 39.54414], [46.51027, 39.52373], [46.53051, 39.47809], [46.4013, 39.45405], [46.37795, 39.42039], [46.43244, 39.35181], [46.50093, 39.33736], [46.56476, 39.24942], [46.63481, 39.23013], [46.58032, 39.21204], [46.54141, 39.15895], [46.52584, 39.18912], [46.44022, 39.19636], [46.54296, 39.07078], [46.51805, 38.94982], [46.53497, 38.86548], [46.75752, 39.03231], [46.83822, 39.13143], [46.92539, 39.16644], [46.95341, 39.13505], [47.05771, 39.20143], [47.05927, 39.24846], [47.31301, 39.37492], [47.38978, 39.45999], [47.50099, 39.49615], [47.84774, 39.66285], [47.98977, 39.70999], [48.34264, 39.42935], [48.37385, 39.37584], [48.15984, 39.30028], [48.12404, 39.25208], [48.15361, 39.19419], [48.31239, 39.09278], [48.33884, 39.03022], [48.28437, 38.97186], [48.08627, 38.94434], [48.07734, 38.91616], [48.01409, 38.90333], [48.02581, 38.82705], [48.24773, 38.71883], [48.3146, 38.59958], [48.45084, 38.61013], [48.58793, 38.45076], [48.62217, 38.40198], [48.70001, 38.40564], [48.78979, 38.45026], [48.81072, 38.44853], [48.84969, 38.45015], [48.88288, 38.43975], [52.39847, 39.43556], [48.80971, 41.95365], [48.5867, 41.84306], [48.55078, 41.77917], [48.42301, 41.65444], [48.40277, 41.60441], [48.2878, 41.56221], [48.22064, 41.51472], [48.07587, 41.49957], [47.87973, 41.21798], [47.75831, 41.19455], [47.62288, 41.22969], [47.54504, 41.20275], [47.49004, 41.26366], [47.34579, 41.27884], [47.10762, 41.59044], [47.03757, 41.55434], [46.99554, 41.59743], [47.00955, 41.63583], [46.8134, 41.76252], [46.75269, 41.8623], [46.58924, 41.80547], [46.5332, 41.87389], [46.42738, 41.91323]], [[45.50279, 40.58424], [45.47927, 40.65023], [45.51825, 40.67382], [45.56071, 40.64765], [45.50279, 40.58424]]], [[[45.00864, 41.03411], [45.03792, 41.03938], [45.04517, 41.06653], [45.03406, 41.07931], [45.00864, 41.09407], [44.97169, 41.09176], [44.95383, 41.07553], [44.96031, 41.06345], [44.9903, 41.05657], [45.00864, 41.03411]]], [[[45.21324, 40.9817], [45.23095, 40.97828], [45.23487, 41.00226], [45.20625, 41.01484], [45.18382, 41.0066], [45.19312, 40.98998], [45.20518, 40.99348], [45.21219, 40.99001], [45.21324, 40.9817]]], [[[45.46992, 39.49888], [45.29606, 39.57654], [45.30385, 39.61373], [45.23535, 39.61373], [45.21784, 39.58074], [45.17464, 39.58614], [45.18554, 39.67846], [45.06604, 39.79277], [44.92869, 39.72157], [44.88354, 39.74432], [44.75779, 39.7148], [44.80977, 39.65768], [44.81043, 39.62677], [44.88916, 39.59653], [44.96746, 39.42998], [45.05932, 39.36435], [45.08751, 39.35052], [45.16168, 39.21952], [45.30489, 39.18333], [45.40148, 39.09007], [45.40452, 39.07224], [45.44811, 39.04927], [45.44966, 38.99243], [45.6131, 38.964], [45.6155, 38.94304], [45.65172, 38.95199], [45.83883, 38.90768], [45.90266, 38.87739], [45.94624, 38.89072], [46.00228, 38.87376], [46.06766, 38.87861], [46.14785, 38.84206], [46.06973, 39.0744], [46.02303, 39.09978], [45.99774, 39.28931], [45.79225, 39.3695], [45.83, 39.46487], [45.80804, 39.56716], [45.70547, 39.60174], [45.46992, 39.49888]]]]
24087 nameEn: "Bosnia and Herzegovina",
24088 groups: ["039", "150", "UN"],
24089 callingCodes: ["387"]
24092 type: "MultiPolygon",
24093 coordinates: [[[[17.84826, 45.04489], [17.66571, 45.13408], [17.59104, 45.10816], [17.51469, 45.10791], [17.47589, 45.12656], [17.45615, 45.12523], [17.4498, 45.16119], [17.41229, 45.13335], [17.33573, 45.14521], [17.32092, 45.16246], [17.26815, 45.18444], [17.25131, 45.14957], [17.24325, 45.146], [17.18438, 45.14764], [17.0415, 45.20759], [16.9385, 45.22742], [16.92405, 45.27607], [16.83804, 45.18951], [16.81137, 45.18434], [16.78219, 45.19002], [16.74845, 45.20393], [16.64962, 45.20714], [16.60194, 45.23042], [16.56559, 45.22307], [16.5501, 45.2212], [16.52982, 45.22713], [16.49155, 45.21153], [16.4634, 45.14522], [16.40023, 45.1147], [16.38309, 45.05955], [16.38219, 45.05139], [16.3749, 45.05206], [16.35863, 45.03529], [16.35404, 45.00241], [16.29036, 44.99732], [16.12153, 45.09616], [15.98412, 45.23088], [15.83512, 45.22459], [15.76371, 45.16508], [15.78842, 45.11519], [15.74585, 45.0638], [15.78568, 44.97401], [15.74723, 44.96818], [15.76096, 44.87045], [15.79472, 44.8455], [15.72584, 44.82334], [15.8255, 44.71501], [15.89348, 44.74964], [16.05828, 44.61538], [16.00884, 44.58605], [16.03012, 44.55572], [16.10566, 44.52586], [16.16814, 44.40679], [16.12969, 44.38275], [16.21346, 44.35231], [16.18688, 44.27012], [16.36864, 44.08263], [16.43662, 44.07523], [16.43629, 44.02826], [16.50528, 44.0244], [16.55472, 43.95326], [16.70922, 43.84887], [16.75316, 43.77157], [16.80736, 43.76011], [17.00585, 43.58037], [17.15828, 43.49376], [17.24411, 43.49376], [17.29699, 43.44542], [17.25579, 43.40353], [17.286, 43.33065], [17.46986, 43.16559], [17.64268, 43.08595], [17.70879, 42.97223], [17.5392, 42.92787], [17.6444, 42.88641], [17.68151, 42.92725], [17.7948, 42.89556], [17.80854, 42.9182], [17.88201, 42.83668], [18.24318, 42.6112], [18.36197, 42.61423], [18.43735, 42.55921], [18.49778, 42.58409], [18.53751, 42.57376], [18.55504, 42.58409], [18.52232, 42.62279], [18.57373, 42.64429], [18.54841, 42.68328], [18.54603, 42.69171], [18.55221, 42.69045], [18.56789, 42.72074], [18.47324, 42.74992], [18.45921, 42.81682], [18.47633, 42.85829], [18.4935, 42.86433], [18.49661, 42.89306], [18.49076, 42.95553], [18.52232, 43.01451], [18.66254, 43.03928], [18.64735, 43.14766], [18.66605, 43.2056], [18.71747, 43.2286], [18.6976, 43.25243], [18.76538, 43.29838], [18.85342, 43.32426], [18.84794, 43.33735], [18.83912, 43.34795], [18.90911, 43.36383], [18.95819, 43.32899], [18.95001, 43.29327], [19.00844, 43.24988], [19.04233, 43.30008], [19.08206, 43.29668], [19.08673, 43.31453], [19.04071, 43.397], [19.01078, 43.43854], [18.96053, 43.45042], [18.95469, 43.49367], [18.91379, 43.50299], [19.01078, 43.55806], [19.04934, 43.50384], [19.13933, 43.5282], [19.15685, 43.53943], [19.22807, 43.5264], [19.24774, 43.53061], [19.2553, 43.5938], [19.33426, 43.58833], [19.36653, 43.60921], [19.41941, 43.54056], [19.42696, 43.57987], [19.50455, 43.58385], [19.5176, 43.71403], [19.3986, 43.79668], [19.23465, 43.98764], [19.24363, 44.01502], [19.38439, 43.96611], [19.52515, 43.95573], [19.56498, 43.99922], [19.61836, 44.01464], [19.61991, 44.05254], [19.57467, 44.04716], [19.55999, 44.06894], [19.51167, 44.08158], [19.47321, 44.1193], [19.48386, 44.14332], [19.47338, 44.15034], [19.43905, 44.13088], [19.40927, 44.16722], [19.3588, 44.18353], [19.34773, 44.23244], [19.32464, 44.27185], [19.26945, 44.26957], [19.23306, 44.26097], [19.20508, 44.2917], [19.18328, 44.28383], [19.16741, 44.28648], [19.13332, 44.31492], [19.13556, 44.338], [19.11547, 44.34218], [19.1083, 44.3558], [19.11865, 44.36712], [19.10298, 44.36924], [19.10365, 44.37795], [19.10704, 44.38249], [19.10749, 44.39421], [19.11785, 44.40313], [19.14681, 44.41463], [19.14837, 44.45253], [19.12278, 44.50132], [19.13369, 44.52521], [19.16699, 44.52197], [19.26388, 44.65412], [19.32543, 44.74058], [19.36722, 44.88164], [19.18183, 44.92055], [19.01994, 44.85493], [18.8704, 44.85097], [18.76347, 44.90669], [18.76369, 44.93707], [18.80661, 44.93561], [18.78357, 44.97741], [18.65723, 45.07544], [18.47939, 45.05871], [18.41896, 45.11083], [18.32077, 45.1021], [18.24387, 45.13699], [18.1624, 45.07654], [18.03121, 45.12632], [18.01594, 45.15163], [17.99479, 45.14958], [17.97834, 45.13831], [17.97336, 45.12245], [17.93706, 45.08016], [17.87148, 45.04645], [17.84826, 45.04489]]]]
24102 nameEn: "Barbados",
24103 groups: ["029", "003", "419", "019", "UN"],
24105 callingCodes: ["1 246"]
24108 type: "MultiPolygon",
24109 coordinates: [[[[-58.56442, 13.24471], [-59.80731, 13.87556], [-59.82929, 12.70644], [-58.56442, 13.24471]]]]
24118 nameEn: "Bangladesh",
24119 groups: ["034", "142", "UN"],
24121 callingCodes: ["880"]
24124 type: "MultiPolygon",
24125 coordinates: [[[[89.15869, 26.13708], [89.08899, 26.38845], [88.95612, 26.4564], [88.92357, 26.40711], [88.91321, 26.37984], [89.05328, 26.2469], [88.85004, 26.23211], [88.78961, 26.31093], [88.67837, 26.26291], [88.69485, 26.38353], [88.62144, 26.46783], [88.4298, 26.54489], [88.41196, 26.63837], [88.33093, 26.48929], [88.35153, 26.45241], [88.36938, 26.48683], [88.48749, 26.45855], [88.51649, 26.35923], [88.35153, 26.29123], [88.34757, 26.22216], [88.1844, 26.14417], [88.16581, 26.0238], [88.08804, 25.91334], [88.13138, 25.78773], [88.242, 25.80811], [88.45103, 25.66245], [88.4559, 25.59227], [88.677, 25.46959], [88.81296, 25.51546], [88.85278, 25.34679], [89.01105, 25.30303], [89.00463, 25.26583], [88.94067, 25.18534], [88.44766, 25.20149], [88.46277, 25.07468], [88.33917, 24.86803], [88.27325, 24.88796], [88.21832, 24.96642], [88.14004, 24.93529], [88.15515, 24.85806], [88.00683, 24.66477], [88.08786, 24.63232], [88.12296, 24.51301], [88.50934, 24.32474], [88.68801, 24.31464], [88.74841, 24.1959], [88.6976, 24.14703], [88.73743, 23.91751], [88.66189, 23.87607], [88.58087, 23.87105], [88.56507, 23.64044], [88.74841, 23.47361], [88.79351, 23.50535], [88.79254, 23.46028], [88.71133, 23.2492], [88.99148, 23.21134], [88.86377, 23.08759], [88.88327, 23.03885], [88.87063, 22.95235], [88.96713, 22.83346], [88.9151, 22.75228], [88.94614, 22.66941], [88.9367, 22.58527], [89.07114, 22.15335], [89.08044, 21.41871], [92.47409, 20.38654], [92.26071, 21.05697], [92.17752, 21.17445], [92.20087, 21.337], [92.37939, 21.47764], [92.43158, 21.37025], [92.55105, 21.3856], [92.60187, 21.24615], [92.68152, 21.28454], [92.59775, 21.6092], [92.62187, 21.87037], [92.60949, 21.97638], [92.56616, 22.13554], [92.60029, 22.1522], [92.5181, 22.71441], [92.37665, 22.9435], [92.38214, 23.28705], [92.26541, 23.70392], [92.15417, 23.73409], [92.04706, 23.64229], [91.95093, 23.73284], [91.95642, 23.47361], [91.84789, 23.42235], [91.76417, 23.26619], [91.81634, 23.08001], [91.7324, 23.00043], [91.61571, 22.93929], [91.54993, 23.01051], [91.46615, 23.2328], [91.4035, 23.27522], [91.40848, 23.07117], [91.36453, 23.06612], [91.28293, 23.37538], [91.15579, 23.6599], [91.25192, 23.83463], [91.22308, 23.89616], [91.29587, 24.0041], [91.35741, 23.99072], [91.37414, 24.10693], [91.55542, 24.08687], [91.63782, 24.1132], [91.65292, 24.22095], [91.73257, 24.14703], [91.76004, 24.23848], [91.82596, 24.22345], [91.89258, 24.14674], [91.96603, 24.3799], [92.11662, 24.38997], [92.15796, 24.54435], [92.25854, 24.9191], [92.38626, 24.86055], [92.49887, 24.88796], [92.39147, 25.01471], [92.33957, 25.07593], [92.0316, 25.1834], [91.63648, 25.12846], [91.25517, 25.20677], [90.87427, 25.15799], [90.65042, 25.17788], [90.40034, 25.1534], [90.1155, 25.22686], [89.90478, 25.31038], [89.87629, 25.28337], [89.83371, 25.29548], [89.84086, 25.31854], [89.81208, 25.37244], [89.86129, 25.61714], [89.84388, 25.70042], [89.80585, 25.82489], [89.86592, 25.93115], [89.77728, 26.04254], [89.77865, 26.08387], [89.73581, 26.15818], [89.70201, 26.15138], [89.63968, 26.22595], [89.57101, 25.9682], [89.53515, 26.00382], [89.35953, 26.0077], [89.15869, 26.13708]]]]
24135 groups: ["EU", "155", "150", "UN"],
24136 callingCodes: ["32"]
24139 type: "MultiPolygon",
24140 coordinates: [[[[4.93295, 51.44945], [4.93909, 51.44632], [4.9524, 51.45014], [4.95244, 51.45207], [4.93295, 51.44945]]], [[[4.91493, 51.4353], [4.92652, 51.43329], [4.92952, 51.42984], [4.93986, 51.43064], [4.94265, 51.44003], [4.93471, 51.43861], [4.93416, 51.44185], [4.94025, 51.44193], [4.93544, 51.44634], [4.92879, 51.44161], [4.92815, 51.43856], [4.92566, 51.44273], [4.92811, 51.4437], [4.92287, 51.44741], [4.91811, 51.44621], [4.92227, 51.44252], [4.91935, 51.43634], [4.91493, 51.4353]]], [[[4.82946, 51.4213], [4.82409, 51.44736], [4.84139, 51.4799], [4.78803, 51.50284], [4.77321, 51.50529], [4.74578, 51.48937], [4.72935, 51.48424], [4.65442, 51.42352], [4.57489, 51.4324], [4.53521, 51.4243], [4.52846, 51.45002], [4.54675, 51.47265], [4.5388, 51.48184], [4.47736, 51.4778], [4.38122, 51.44905], [4.39747, 51.43316], [4.38064, 51.41965], [4.43777, 51.36989], [4.39292, 51.35547], [4.34086, 51.35738], [4.33265, 51.37687], [4.21923, 51.37443], [4.24024, 51.35371], [4.16721, 51.29348], [4.05165, 51.24171], [4.01957, 51.24504], [3.97889, 51.22537], [3.90125, 51.20371], [3.78783, 51.2151], [3.78999, 51.25766], [3.58939, 51.30064], [3.51502, 51.28697], [3.52698, 51.2458], [3.43488, 51.24135], [3.41704, 51.25933], [3.38289, 51.27331], [3.35847, 51.31572], [3.38696, 51.33436], [3.36263, 51.37112], [2.56575, 51.85301], [2.18458, 51.52087], [2.55904, 51.07014], [2.57551, 51.00326], [2.63074, 50.94746], [2.59093, 50.91751], [2.63331, 50.81457], [2.71165, 50.81295], [2.81056, 50.71773], [2.8483, 50.72276], [2.86985, 50.7033], [2.87937, 50.70298], [2.88504, 50.70656], [2.90069, 50.69263], [2.91036, 50.6939], [2.90873, 50.702], [2.95019, 50.75138], [2.96778, 50.75242], [3.00537, 50.76588], [3.04314, 50.77674], [3.09163, 50.77717], [3.10614, 50.78303], [3.11206, 50.79416], [3.11987, 50.79188], [3.1257, 50.78603], [3.15017, 50.79031], [3.16476, 50.76843], [3.18339, 50.74981], [3.18811, 50.74025], [3.20064, 50.73547], [3.19017, 50.72569], [3.20845, 50.71662], [3.22042, 50.71019], [3.24593, 50.71389], [3.26063, 50.70086], [3.26141, 50.69151], [3.2536, 50.68977], [3.264, 50.67668], [3.23951, 50.6585], [3.2729, 50.60718], [3.28575, 50.52724], [3.37693, 50.49538], [3.44629, 50.51009], [3.47385, 50.53397], [3.51564, 50.5256], [3.49509, 50.48885], [3.5683, 50.50192], [3.58361, 50.49049], [3.61014, 50.49568], [3.64426, 50.46275], [3.66153, 50.45165], [3.67494, 50.40239], [3.67262, 50.38663], [3.65709, 50.36873], [3.66976, 50.34563], [3.71009, 50.30305], [3.70987, 50.3191], [3.73911, 50.34809], [3.84314, 50.35219], [3.90781, 50.32814], [3.96771, 50.34989], [4.0268, 50.35793], [4.0689, 50.3254], [4.10237, 50.31247], [4.10957, 50.30234], [4.11954, 50.30425], [4.13665, 50.25609], [4.16808, 50.25786], [4.15524, 50.2833], [4.17347, 50.28838], [4.17861, 50.27443], [4.20651, 50.27333], [4.21945, 50.25539], [4.15524, 50.21103], [4.16014, 50.19239], [4.13561, 50.13078], [4.20147, 50.13535], [4.23101, 50.06945], [4.16294, 50.04719], [4.13508, 50.01976], [4.14239, 49.98034], [4.20532, 49.95803], [4.31963, 49.97043], [4.35051, 49.95315], [4.43488, 49.94122], [4.51098, 49.94659], [4.5414, 49.96911], [4.68695, 49.99685], [4.70064, 50.09384], [4.75237, 50.11314], [4.82438, 50.16878], [4.83279, 50.15331], [4.88602, 50.15182], [4.8382, 50.06738], [4.78827, 49.95609], [4.88529, 49.9236], [4.85134, 49.86457], [4.86965, 49.82271], [4.85464, 49.78995], [4.96714, 49.79872], [5.09249, 49.76193], [5.14545, 49.70287], [5.26232, 49.69456], [5.31465, 49.66846], [5.33039, 49.6555], [5.30214, 49.63055], [5.3137, 49.61225], [5.33851, 49.61599], [5.34837, 49.62889], [5.3974, 49.61596], [5.43713, 49.5707], [5.46734, 49.52648], [5.46541, 49.49825], [5.55001, 49.52729], [5.60909, 49.51228], [5.64505, 49.55146], [5.75649, 49.54321], [5.7577, 49.55915], [5.77435, 49.56298], [5.79195, 49.55228], [5.81838, 49.54777], [5.84143, 49.5533], [5.84692, 49.55663], [5.8424, 49.56082], [5.87256, 49.57539], [5.86986, 49.58756], [5.84971, 49.58674], [5.84826, 49.5969], [5.8762, 49.60898], [5.87609, 49.62047], [5.88393, 49.62802], [5.88552, 49.63507], [5.90599, 49.63853], [5.90164, 49.6511], [5.9069, 49.66377], [5.86175, 49.67862], [5.86527, 49.69291], [5.88677, 49.70951], [5.86503, 49.72739], [5.84193, 49.72161], [5.82562, 49.72395], [5.83149, 49.74729], [5.82245, 49.75048], [5.78871, 49.7962], [5.75409, 49.79239], [5.74953, 49.81428], [5.74364, 49.82058], [5.74844, 49.82435], [5.7404, 49.83452], [5.74076, 49.83823], [5.74975, 49.83933], [5.74953, 49.84709], [5.75884, 49.84811], [5.74567, 49.85368], [5.75861, 49.85631], [5.75269, 49.8711], [5.78415, 49.87922], [5.73621, 49.89796], [5.77314, 49.93646], [5.77291, 49.96056], [5.80833, 49.96451], [5.81163, 49.97142], [5.83467, 49.97823], [5.83968, 49.9892], [5.82331, 49.99662], [5.81866, 50.01286], [5.8551, 50.02683], [5.86904, 50.04614], [5.85474, 50.06342], [5.8857, 50.07824], [5.89488, 50.11476], [5.95929, 50.13295], [5.96453, 50.17259], [6.02488, 50.18283], [6.03093, 50.16362], [6.06406, 50.15344], [6.08577, 50.17246], [6.12028, 50.16374], [6.1137, 50.13668], [6.1379, 50.12964], [6.15298, 50.14126], [6.14132, 50.14971], [6.14588, 50.17106], [6.18739, 50.1822], [6.18364, 50.20815], [6.16853, 50.2234], [6.208, 50.25179], [6.28797, 50.27458], [6.29949, 50.30887], [6.32488, 50.32333], [6.35701, 50.31139], [6.40641, 50.32425], [6.40785, 50.33557], [6.3688, 50.35898], [6.34406, 50.37994], [6.36852, 50.40776], [6.37219, 50.45397], [6.34005, 50.46083], [6.3465, 50.48833], [6.30809, 50.50058], [6.26637, 50.50272], [6.22335, 50.49578], [6.20599, 50.52089], [6.19193, 50.5212], [6.18716, 50.52653], [6.19579, 50.5313], [6.19735, 50.53576], [6.17802, 50.54179], [6.17739, 50.55875], [6.20281, 50.56952], [6.22581, 50.5907], [6.24005, 50.58732], [6.24888, 50.59869], [6.2476, 50.60392], [6.26957, 50.62444], [6.17852, 50.6245], [6.11707, 50.72231], [6.04428, 50.72861], [6.0406, 50.71848], [6.0326, 50.72647], [6.03889, 50.74618], [6.01976, 50.75398], [5.97545, 50.75441], [5.95942, 50.7622], [5.89132, 50.75124], [5.89129, 50.75125], [5.88734, 50.77092], [5.84888, 50.75448], [5.84548, 50.76542], [5.80673, 50.7558], [5.77513, 50.78308], [5.76533, 50.78159], [5.74356, 50.7691], [5.73904, 50.75674], [5.72216, 50.76398], [5.69469, 50.75529], [5.68091, 50.75804], [5.70107, 50.7827], [5.68995, 50.79641], [5.70118, 50.80764], [5.65259, 50.82309], [5.64009, 50.84742], [5.64504, 50.87107], [5.67886, 50.88142], [5.69858, 50.91046], [5.71626, 50.90796], [5.72644, 50.91167], [5.72545, 50.92312], [5.74644, 50.94723], [5.75927, 50.95601], [5.74752, 50.96202], [5.72875, 50.95428], [5.71864, 50.96092], [5.76242, 50.99703], [5.77688, 51.02483], [5.75961, 51.03113], [5.77258, 51.06196], [5.79835, 51.05834], [5.79903, 51.09371], [5.82921, 51.09328], [5.83226, 51.10585], [5.8109, 51.10861], [5.80798, 51.11661], [5.85508, 51.14445], [5.82564, 51.16753], [5.77697, 51.1522], [5.77735, 51.17845], [5.74617, 51.18928], [5.70344, 51.1829], [5.65528, 51.18736], [5.65145, 51.19788], [5.5603, 51.22249], [5.5569, 51.26544], [5.515, 51.29462], [5.48476, 51.30053], [5.46519, 51.2849], [5.4407, 51.28169], [5.41672, 51.26248], [5.347, 51.27502], [5.33886, 51.26314], [5.29716, 51.26104], [5.26461, 51.26693], [5.23814, 51.26064], [5.22542, 51.26888], [5.24244, 51.30495], [5.2002, 51.32243], [5.16222, 51.31035], [5.13377, 51.31592], [5.13105, 51.34791], [5.07102, 51.39469], [5.10456, 51.43163], [5.07891, 51.4715], [5.04774, 51.47022], [5.03281, 51.48679], [5.0106, 51.47167], [5.00393, 51.44406], [4.92152, 51.39487], [4.90016, 51.41404], [4.84988, 51.41502], [4.78941, 51.41102], [4.77229, 51.41337], [4.76577, 51.43046], [4.78314, 51.43319], [4.82946, 51.4213]]]]
24149 nameEn: "Burkina Faso",
24150 groups: ["011", "202", "002", "UN"],
24151 callingCodes: ["226"]
24154 type: "MultiPolygon",
24155 coordinates: [[[[0.23859, 15.00135], [0.06588, 14.96961], [-0.24673, 15.07805], [-0.72004, 15.08655], [-1.05875, 14.7921], [-1.32166, 14.72774], [-1.68083, 14.50023], [-1.97945, 14.47709], [-1.9992, 14.19011], [-2.10223, 14.14878], [-2.47587, 14.29671], [-2.66175, 14.14713], [-2.84667, 14.05532], [-2.90831, 13.81174], [-2.88189, 13.64921], [-3.26407, 13.70699], [-3.28396, 13.5422], [-3.23599, 13.29035], [-3.43507, 13.27272], [-3.4313, 13.1588], [-3.54454, 13.1781], [-3.7911, 13.36665], [-3.96282, 13.38164], [-3.90558, 13.44375], [-3.96501, 13.49778], [-4.34477, 13.12927], [-4.21819, 12.95722], [-4.238, 12.71467], [-4.47356, 12.71252], [-4.41412, 12.31922], [-4.57703, 12.19875], [-4.54841, 12.1385], [-4.62546, 12.13204], [-4.62987, 12.06531], [-4.70692, 12.06746], [-4.72893, 12.01579], [-5.07897, 11.97918], [-5.26389, 11.84778], [-5.40258, 11.8327], [-5.26389, 11.75728], [-5.29251, 11.61715], [-5.22867, 11.60421], [-5.20665, 11.43811], [-5.25509, 11.36905], [-5.25949, 11.24816], [-5.32553, 11.21578], [-5.32994, 11.13371], [-5.49284, 11.07538], [-5.41579, 10.84628], [-5.47083, 10.75329], [-5.46643, 10.56074], [-5.51058, 10.43177], [-5.39602, 10.2929], [-5.12465, 10.29788], [-4.96453, 9.99923], [-4.96621, 9.89132], [-4.6426, 9.70696], [-4.31392, 9.60062], [-4.25999, 9.76012], [-3.69703, 9.94279], [-3.31779, 9.91125], [-3.27228, 9.84981], [-3.19306, 9.93781], [-3.16609, 9.85147], [-3.00765, 9.74019], [-2.93012, 9.57403], [-2.76494, 9.40778], [-2.68802, 9.49343], [-2.76534, 9.56589], [-2.74174, 9.83172], [-2.83108, 10.40252], [-2.94232, 10.64281], [-2.83373, 11.0067], [-0.67143, 10.99811], [-0.61937, 10.91305], [-0.44298, 11.04292], [-0.42391, 11.11661], [-0.38219, 11.12596], [-0.35955, 11.07801], [-0.28566, 11.12713], [-0.27374, 11.17157], [-0.13493, 11.14075], [0.50388, 11.01011], [0.48852, 10.98561], [0.50521, 10.98035], [0.4958, 10.93269], [0.66104, 10.99964], [0.91245, 10.99597], [0.9813, 11.08876], [1.03409, 11.04719], [1.42823, 11.46822], [2.00988, 11.42227], [2.29983, 11.68254], [2.39723, 11.89473], [2.05785, 12.35539], [2.26349, 12.41915], [0.99167, 13.10727], [0.99253, 13.37515], [1.18873, 13.31771], [1.21217, 13.37853], [1.24516, 13.33968], [1.28509, 13.35488], [1.24429, 13.39373], [1.20088, 13.38951], [1.02813, 13.46635], [0.99514, 13.5668], [0.77637, 13.64442], [0.77377, 13.6866], [0.61924, 13.68491], [0.38051, 14.05575], [0.16936, 14.51654], [0.23859, 15.00135]]]]
24164 nameEn: "Bulgaria",
24165 groups: ["EU", "151", "150", "UN"],
24166 callingCodes: ["359"]
24169 type: "MultiPolygon",
24170 coordinates: [[[[23.05288, 43.79494], [22.85314, 43.84452], [22.83753, 43.88055], [22.87873, 43.9844], [23.01674, 44.01946], [23.04988, 44.07694], [22.67173, 44.21564], [22.61711, 44.16938], [22.61688, 44.06534], [22.41449, 44.00514], [22.35558, 43.81281], [22.41043, 43.69566], [22.47582, 43.6558], [22.53397, 43.47225], [22.82036, 43.33665], [22.89727, 43.22417], [23.00806, 43.19279], [22.98104, 43.11199], [22.89521, 43.03625], [22.78397, 42.98253], [22.74826, 42.88701], [22.54302, 42.87774], [22.43309, 42.82057], [22.4997, 42.74144], [22.43983, 42.56851], [22.55669, 42.50144], [22.51961, 42.3991], [22.47498, 42.3915], [22.45919, 42.33822], [22.34773, 42.31725], [22.38136, 42.30339], [22.47251, 42.20393], [22.50289, 42.19527], [22.51224, 42.15457], [22.67701, 42.06614], [22.86749, 42.02275], [22.90254, 41.87587], [22.96682, 41.77137], [23.01239, 41.76527], [23.03342, 41.71034], [22.95513, 41.63265], [22.96331, 41.35782], [22.93334, 41.34104], [23.1833, 41.31755], [23.21953, 41.33773], [23.22771, 41.37106], [23.31301, 41.40525], [23.33639, 41.36317], [23.40416, 41.39999], [23.52453, 41.40262], [23.63203, 41.37632], [23.67644, 41.41139], [23.76525, 41.40175], [23.80148, 41.43943], [23.89613, 41.45257], [23.91483, 41.47971], [23.96975, 41.44118], [24.06908, 41.46132], [24.06323, 41.53222], [24.10063, 41.54796], [24.18126, 41.51735], [24.27124, 41.57682], [24.30513, 41.51297], [24.52599, 41.56808], [24.61129, 41.42278], [24.71529, 41.41928], [24.8041, 41.34913], [24.82514, 41.4035], [24.86136, 41.39298], [24.90928, 41.40876], [24.942, 41.38685], [25.11611, 41.34212], [25.28322, 41.23411], [25.48187, 41.28506], [25.52394, 41.2798], [25.55082, 41.31667], [25.61042, 41.30614], [25.66183, 41.31316], [25.70507, 41.29209], [25.8266, 41.34563], [25.87919, 41.30526], [26.12926, 41.35878], [26.16548, 41.42278], [26.20288, 41.43943], [26.14796, 41.47533], [26.176, 41.50072], [26.17951, 41.55409], [26.14328, 41.55496], [26.15146, 41.60828], [26.07083, 41.64584], [26.06148, 41.70345], [26.16841, 41.74858], [26.21325, 41.73223], [26.22888, 41.74139], [26.2654, 41.71544], [26.30255, 41.70925], [26.35957, 41.71149], [26.32952, 41.73637], [26.33589, 41.76802], [26.36952, 41.82265], [26.53968, 41.82653], [26.57961, 41.90024], [26.56051, 41.92995], [26.62996, 41.97644], [26.79143, 41.97386], [26.95638, 42.00741], [27.03277, 42.0809], [27.08486, 42.08735], [27.19251, 42.06028], [27.22376, 42.10152], [27.27411, 42.10409], [27.45478, 41.96591], [27.52379, 41.93756], [27.55191, 41.90928], [27.69949, 41.97515], [27.81235, 41.94803], [27.83492, 41.99709], [27.91479, 41.97902], [28.02971, 41.98066], [28.32297, 41.98371], [29.24336, 43.70874], [28.23293, 43.76], [27.99558, 43.84193], [27.92008, 44.00761], [27.73468, 43.95326], [27.64542, 44.04958], [27.60834, 44.01206], [27.39757, 44.0141], [27.26845, 44.12602], [26.95141, 44.13555], [26.62712, 44.05698], [26.38764, 44.04356], [26.10115, 43.96908], [26.05584, 43.90925], [25.94911, 43.85745], [25.72792, 43.69263], [25.39528, 43.61866], [25.17144, 43.70261], [25.10718, 43.6831], [24.96682, 43.72693], [24.73542, 43.68523], [24.62281, 43.74082], [24.50264, 43.76314], [24.35364, 43.70211], [24.18149, 43.68218], [23.73978, 43.80627], [23.61687, 43.79289], [23.4507, 43.84936], [23.26772, 43.84843], [23.05288, 43.79494]]]]
24180 groups: ["145", "142", "UN"],
24181 callingCodes: ["973"]
24184 type: "MultiPolygon",
24185 coordinates: [[[[50.93865, 26.30758], [50.71771, 26.73086], [50.38162, 26.53976], [50.26923, 26.08243], [50.302, 25.87592], [50.57069, 25.57887], [50.80824, 25.54641], [50.7801, 25.595], [50.86149, 25.6965], [50.81266, 25.88946], [50.93865, 26.30758]]]]
24195 groups: ["014", "202", "002", "UN"],
24196 callingCodes: ["257"]
24199 type: "MultiPolygon",
24200 coordinates: [[[[30.54501, -2.41404], [30.42933, -2.31064], [30.14034, -2.43626], [29.95911, -2.33348], [29.88237, -2.75105], [29.36805, -2.82933], [29.32234, -2.6483], [29.0562, -2.58632], [29.04081, -2.7416], [29.00167, -2.78523], [29.00404, -2.81978], [29.0505, -2.81774], [29.09119, -2.87871], [29.09797, -2.91935], [29.16037, -2.95457], [29.17258, -2.99385], [29.25633, -3.05471], [29.21463, -3.3514], [29.23708, -3.75856], [29.43673, -4.44845], [29.63827, -4.44681], [29.75109, -4.45836], [29.77289, -4.41733], [29.82885, -4.36153], [29.88172, -4.35743], [30.03323, -4.26631], [30.22042, -4.01738], [30.45915, -3.56532], [30.84165, -3.25152], [30.83823, -2.97837], [30.6675, -2.98987], [30.57926, -2.89791], [30.4987, -2.9573], [30.40662, -2.86151], [30.52747, -2.65841], [30.41789, -2.66266], [30.54501, -2.41404]]]]
24211 groups: ["011", "202", "002", "UN"],
24212 callingCodes: ["229"]
24215 type: "MultiPolygon",
24216 coordinates: [[[[3.59375, 11.70269], [3.48187, 11.86092], [3.31613, 11.88495], [3.25352, 12.01467], [2.83978, 12.40585], [2.6593, 12.30631], [2.37783, 12.24804], [2.39657, 12.10952], [2.45824, 11.98672], [2.39723, 11.89473], [2.29983, 11.68254], [2.00988, 11.42227], [1.42823, 11.46822], [1.03409, 11.04719], [0.9813, 11.08876], [0.91245, 10.99597], [0.8804, 10.803], [0.80358, 10.71459], [0.77666, 10.37665], [1.35507, 9.99525], [1.36624, 9.5951], [1.33675, 9.54765], [1.41746, 9.3226], [1.5649, 9.16941], [1.61838, 9.0527], [1.64249, 6.99562], [1.55877, 6.99737], [1.61812, 6.74843], [1.58105, 6.68619], [1.76906, 6.43189], [1.79826, 6.28221], [1.62913, 6.24075], [1.67336, 6.02702], [2.74181, 6.13349], [2.70566, 6.38038], [2.70464, 6.50831], [2.74334, 6.57291], [2.7325, 6.64057], [2.78204, 6.70514], [2.78823, 6.76356], [2.73405, 6.78508], [2.74024, 6.92802], [2.71702, 6.95722], [2.76965, 7.13543], [2.74489, 7.42565], [2.79442, 7.43486], [2.78668, 7.5116], [2.73405, 7.5423], [2.73095, 7.7755], [2.67523, 7.87825], [2.77907, 9.06924], [3.08017, 9.10006], [3.14147, 9.28375], [3.13928, 9.47167], [3.25093, 9.61632], [3.34726, 9.70696], [3.32099, 9.78032], [3.35383, 9.83641], [3.54429, 9.87739], [3.66908, 10.18136], [3.57275, 10.27185], [3.6844, 10.46351], [3.78292, 10.40538], [3.84243, 10.59316], [3.71505, 11.13015], [3.49175, 11.29765], [3.59375, 11.70269]]]]
24224 wikidata: "Q25362",
24225 nameEn: "Saint-Barth\xE9lemy",
24227 groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24228 callingCodes: ["590"]
24231 type: "MultiPolygon",
24232 coordinates: [[[[-62.62718, 18.26185], [-63.1055, 17.86651], [-62.34423, 17.49165], [-62.62718, 18.26185]]]]
24240 wikidata: "Q23635",
24243 groups: ["BOTS", "021", "003", "019", "UN"],
24245 callingCodes: ["1 441"]
24248 type: "MultiPolygon",
24249 coordinates: [[[[-63.20987, 32.6953], [-65.31453, 32.68437], [-65.63955, 31.43417], [-63.20987, 32.6953]]]]
24259 groups: ["Q36117", "035", "142", "UN"],
24261 callingCodes: ["673"]
24264 type: "MultiPolygon",
24265 coordinates: [[[[115.16236, 5.01011], [115.02521, 5.35005], [114.10166, 4.76112], [114.07448, 4.58441], [114.15813, 4.57], [114.26876, 4.49878], [114.32176, 4.34942], [114.32176, 4.2552], [114.4416, 4.27588], [114.49922, 4.13108], [114.64211, 4.00694], [114.78539, 4.12205], [114.88039, 4.4257], [114.83189, 4.42387], [114.77303, 4.72871], [114.8266, 4.75062], [114.88841, 4.81905], [114.96982, 4.81146], [114.99417, 4.88201], [115.05038, 4.90275], [115.02955, 4.82087], [115.02278, 4.74137], [115.04064, 4.63706], [115.07737, 4.53418], [115.09978, 4.39123], [115.31275, 4.30806], [115.36346, 4.33563], [115.2851, 4.42295], [115.27819, 4.63661], [115.20737, 4.8256], [115.15092, 4.87604], [115.16236, 5.01011]]]]
24275 groups: ["005", "419", "019", "UN"],
24276 callingCodes: ["591"]
24279 type: "MultiPolygon",
24280 coordinates: [[[[-63.90248, -12.52544], [-64.22539, -12.45267], [-64.30708, -12.46398], [-64.99778, -11.98604], [-65.30027, -11.48749], [-65.28141, -10.86289], [-65.35402, -10.78685], [-65.37923, -10.35141], [-65.29019, -9.86253], [-65.40615, -9.63894], [-65.56244, -9.84266], [-65.68343, -9.75323], [-67.17784, -10.34016], [-68.71533, -11.14749], [-68.7651, -11.0496], [-68.75179, -11.03688], [-68.75265, -11.02383], [-68.74802, -11.00891], [-69.42792, -10.93451], [-69.47839, -10.95254], [-69.57156, -10.94555], [-68.98115, -11.8979], [-68.65044, -12.50689], [-68.85615, -12.87769], [-68.8864, -13.40792], [-69.05265, -13.68546], [-68.88135, -14.18639], [-69.36254, -14.94634], [-69.14856, -15.23478], [-69.40336, -15.61358], [-69.20291, -16.16668], [-69.09986, -16.22693], [-68.96238, -16.194], [-68.79464, -16.33272], [-68.98358, -16.42165], [-69.04027, -16.57214], [-69.00853, -16.66769], [-69.16896, -16.72233], [-69.62883, -17.28142], [-69.46863, -17.37466], [-69.46897, -17.4988], [-69.46623, -17.60518], [-69.34126, -17.72753], [-69.28671, -17.94844], [-69.07496, -18.03715], [-69.14807, -18.16893], [-69.07432, -18.28259], [-68.94987, -18.93302], [-68.87082, -19.06003], [-68.80602, -19.08355], [-68.61989, -19.27584], [-68.41218, -19.40499], [-68.66761, -19.72118], [-68.54611, -19.84651], [-68.57132, -20.03134], [-68.74273, -20.08817], [-68.7276, -20.46178], [-68.44023, -20.62701], [-68.55383, -20.7355], [-68.53957, -20.91542], [-68.40403, -20.94562], [-68.18816, -21.28614], [-67.85114, -22.87076], [-67.54284, -22.89771], [-67.18382, -22.81525], [-66.7298, -22.23644], [-66.29714, -22.08741], [-66.24077, -21.77837], [-66.03836, -21.84829], [-66.04832, -21.9187], [-65.9261, -21.93335], [-65.7467, -22.10105], [-65.61166, -22.09504], [-65.58694, -22.09794], [-65.57743, -22.07675], [-65.47435, -22.08908], [-64.99524, -22.08255], [-64.90014, -22.12136], [-64.67174, -22.18957], [-64.58888, -22.25035], [-64.4176, -22.67692], [-64.35108, -22.73282], [-64.31489, -22.88824], [-64.22918, -22.55807], [-63.93287, -21.99934], [-63.70963, -21.99934], [-63.68113, -22.0544], [-63.66482, -21.99918], [-62.81124, -21.9987], [-62.8078, -22.12534], [-62.64455, -22.25091], [-62.2757, -21.06657], [-62.26883, -20.55311], [-61.93912, -20.10053], [-61.73723, -19.63958], [-60.00638, -19.2981], [-59.06965, -19.29148], [-58.23216, -19.80058], [-58.16225, -20.16193], [-57.8496, -19.98346], [-58.14215, -19.76276], [-57.78463, -19.03259], [-57.71113, -19.03161], [-57.69134, -19.00544], [-57.71995, -18.97546], [-57.71995, -18.89573], [-57.76764, -18.90087], [-57.56807, -18.25655], [-57.48237, -18.24219], [-57.69877, -17.8431], [-57.73949, -17.56095], [-57.90082, -17.44555], [-57.99661, -17.5273], [-58.32935, -17.28195], [-58.5058, -16.80958], [-58.30918, -16.3699], [-58.32431, -16.25861], [-58.41506, -16.32636], [-60.16069, -16.26479], [-60.23797, -15.50267], [-60.58224, -15.09887], [-60.23968, -15.09515], [-60.27887, -14.63021], [-60.46037, -14.22496], [-60.48053, -13.77981], [-61.05527, -13.50054], [-61.81151, -13.49564], [-63.76259, -12.42952], [-63.90248, -12.52544]]]]
24288 wikidata: "Q27561",
24289 nameEn: "Caribbean Netherlands",
24301 groups: ["005", "419", "019", "UN"],
24302 callingCodes: ["55"]
24305 type: "MultiPolygon",
24306 coordinates: [[[[-59.69361, 4.34069], [-59.78878, 4.45637], [-60.15953, 4.53456], [-60.04189, 4.69801], [-59.98129, 5.07097], [-60.20944, 5.28754], [-60.32352, 5.21299], [-60.73204, 5.20931], [-60.5802, 4.94312], [-60.86539, 4.70512], [-60.98303, 4.54167], [-61.15703, 4.49839], [-61.31457, 4.54167], [-61.29675, 4.44216], [-61.48569, 4.43149], [-61.54629, 4.2822], [-62.13094, 4.08309], [-62.44822, 4.18621], [-62.57656, 4.04754], [-62.74411, 4.03331], [-62.7655, 3.73099], [-62.98296, 3.59935], [-63.21111, 3.96219], [-63.4464, 3.9693], [-63.42233, 3.89995], [-63.50611, 3.83592], [-63.67099, 4.01731], [-63.70218, 3.91417], [-63.86082, 3.94796], [-63.99183, 3.90172], [-64.14512, 4.12932], [-64.57648, 4.12576], [-64.72977, 4.28931], [-64.84028, 4.24665], [-64.48379, 3.7879], [-64.02908, 2.79797], [-64.0257, 2.48156], [-63.39114, 2.4317], [-63.39827, 2.16098], [-64.06135, 1.94722], [-64.08274, 1.64792], [-64.34654, 1.35569], [-64.38932, 1.5125], [-65.11657, 1.12046], [-65.57288, 0.62856], [-65.50158, 0.92086], [-65.6727, 1.01353], [-66.28507, 0.74585], [-66.85795, 1.22998], [-67.08222, 1.17441], [-67.15784, 1.80439], [-67.299, 1.87494], [-67.40488, 2.22258], [-67.9292, 1.82455], [-68.18632, 2.00091], [-68.26699, 1.83463], [-68.18128, 1.72881], [-69.38621, 1.70865], [-69.53746, 1.76408], [-69.83491, 1.69353], [-69.82987, 1.07864], [-69.26017, 1.06856], [-69.14422, 0.84172], [-69.20976, 0.57958], [-69.47696, 0.71065], [-70.04162, 0.55437], [-70.03658, -0.19681], [-69.603, -0.51947], [-69.59796, -0.75136], [-69.4215, -1.01853], [-69.43395, -1.42219], [-69.94708, -4.2431], [-70.00888, -4.37833], [-70.11305, -4.27281], [-70.19582, -4.3607], [-70.33236, -4.15214], [-70.77601, -4.15717], [-70.96814, -4.36915], [-71.87003, -4.51661], [-72.64391, -5.0391], [-72.83973, -5.14765], [-73.24579, -6.05764], [-73.12983, -6.43852], [-73.73986, -6.87919], [-73.77011, -7.28944], [-73.96938, -7.58465], [-73.65485, -7.77897], [-73.76576, -7.89884], [-72.92886, -9.04074], [-73.21498, -9.40904], [-72.72216, -9.41397], [-72.31883, -9.5184], [-72.14742, -9.98049], [-71.23394, -9.9668], [-70.53373, -9.42628], [-70.58453, -9.58303], [-70.55429, -9.76692], [-70.62487, -9.80666], [-70.64134, -11.0108], [-70.51395, -10.92249], [-70.38791, -11.07096], [-69.90896, -10.92744], [-69.57835, -10.94051], [-69.57156, -10.94555], [-69.47839, -10.95254], [-69.42792, -10.93451], [-68.74802, -11.00891], [-68.75265, -11.02383], [-68.75179, -11.03688], [-68.7651, -11.0496], [-68.71533, -11.14749], [-67.17784, -10.34016], [-65.68343, -9.75323], [-65.56244, -9.84266], [-65.40615, -9.63894], [-65.29019, -9.86253], [-65.37923, -10.35141], [-65.35402, -10.78685], [-65.28141, -10.86289], [-65.30027, -11.48749], [-64.99778, -11.98604], [-64.30708, -12.46398], [-64.22539, -12.45267], [-63.90248, -12.52544], [-63.76259, -12.42952], [-61.81151, -13.49564], [-61.05527, -13.50054], [-60.48053, -13.77981], [-60.46037, -14.22496], [-60.27887, -14.63021], [-60.23968, -15.09515], [-60.58224, -15.09887], [-60.23797, -15.50267], [-60.16069, -16.26479], [-58.41506, -16.32636], [-58.32431, -16.25861], [-58.30918, -16.3699], [-58.5058, -16.80958], [-58.32935, -17.28195], [-57.99661, -17.5273], [-57.90082, -17.44555], [-57.73949, -17.56095], [-57.69877, -17.8431], [-57.48237, -18.24219], [-57.56807, -18.25655], [-57.76764, -18.90087], [-57.71995, -18.89573], [-57.71995, -18.97546], [-57.69134, -19.00544], [-57.71113, -19.03161], [-57.78463, -19.03259], [-58.14215, -19.76276], [-57.8496, -19.98346], [-58.16225, -20.16193], [-57.84536, -20.93155], [-57.93492, -21.65505], [-57.88239, -21.6868], [-57.94642, -21.73799], [-57.98625, -22.09157], [-56.6508, -22.28387], [-56.5212, -22.11556], [-56.45893, -22.08072], [-56.23206, -22.25347], [-55.8331, -22.29008], [-55.74941, -22.46436], [-55.741, -22.52018], [-55.72366, -22.5519], [-55.6986, -22.56268], [-55.68742, -22.58407], [-55.62493, -22.62765], [-55.63849, -22.95122], [-55.5446, -23.22811], [-55.52288, -23.2595], [-55.5555, -23.28237], [-55.43585, -23.87157], [-55.44117, -23.9185], [-55.41784, -23.9657], [-55.12292, -23.99669], [-55.0518, -23.98666], [-55.02691, -23.97317], [-54.6238, -23.83078], [-54.32807, -24.01865], [-54.28207, -24.07305], [-54.4423, -25.13381], [-54.62033, -25.46026], [-54.60196, -25.48397], [-54.59509, -25.53696], [-54.59398, -25.59224], [-54.5502, -25.58915], [-54.52926, -25.62846], [-53.90831, -25.55513], [-53.83691, -25.94849], [-53.73511, -26.04211], [-53.73086, -26.05842], [-53.7264, -26.0664], [-53.73391, -26.07006], [-53.73968, -26.10012], [-53.65018, -26.19501], [-53.65237, -26.23289], [-53.63739, -26.2496], [-53.63881, -26.25075], [-53.64632, -26.24798], [-53.64186, -26.25976], [-53.64505, -26.28089], [-53.68269, -26.33359], [-53.73372, -26.6131], [-53.80144, -27.09844], [-54.15978, -27.2889], [-54.19062, -27.27639], [-54.19268, -27.30751], [-54.41888, -27.40882], [-54.50416, -27.48232], [-54.67657, -27.57214], [-54.90159, -27.63132], [-54.90805, -27.73149], [-55.1349, -27.89759], [-55.16872, -27.86224], [-55.33303, -27.94661], [-55.6262, -28.17124], [-55.65418, -28.18304], [-56.01729, -28.51223], [-56.00458, -28.60421], [-56.05265, -28.62651], [-56.54171, -29.11447], [-56.57295, -29.11357], [-56.62789, -29.18073], [-56.81251, -29.48154], [-57.09386, -29.74211], [-57.65132, -30.19229], [-57.22502, -30.26121], [-56.90236, -30.02578], [-56.49267, -30.39471], [-56.4795, -30.3899], [-56.4619, -30.38457], [-55.87388, -31.05053], [-55.58866, -30.84117], [-55.5634, -30.8686], [-55.55373, -30.8732], [-55.55218, -30.88193], [-55.54572, -30.89051], [-55.53431, -30.89714], [-55.53276, -30.90218], [-55.52712, -30.89997], [-55.51862, -30.89828], [-55.50841, -30.9027], [-55.50821, -30.91349], [-54.17384, -31.86168], [-53.76024, -32.0751], [-53.39572, -32.58596], [-53.37671, -32.57005], [-53.1111, -32.71147], [-53.53459, -33.16843], [-53.52794, -33.68908], [-53.44031, -33.69344], [-53.39593, -33.75169], [-53.37138, -33.74313], [-52.83257, -34.01481], [-28.34015, -20.99094], [-28.99601, 1.86593], [-51.35485, 4.8383], [-51.63798, 4.51394], [-51.61983, 4.14596], [-51.79599, 3.89336], [-51.82312, 3.85825], [-51.85573, 3.83427], [-52.31787, 3.17896], [-52.6906, 2.37298], [-52.96539, 2.1881], [-53.78743, 2.34412], [-54.16286, 2.10779], [-54.6084, 2.32856], [-55.01919, 2.564], [-55.71493, 2.40342], [-55.96292, 2.53188], [-56.13054, 2.27723], [-55.92159, 2.05236], [-55.89863, 1.89861], [-55.99278, 1.83137], [-56.47045, 1.95135], [-56.7659, 1.89509], [-57.07092, 1.95304], [-57.09109, 2.01854], [-57.23981, 1.95808], [-57.35073, 1.98327], [-57.55743, 1.69605], [-57.77281, 1.73344], [-57.97336, 1.64566], [-58.01873, 1.51966], [-58.33887, 1.58014], [-58.4858, 1.48399], [-58.53571, 1.29154], [-58.84229, 1.17749], [-58.92072, 1.31293], [-59.25583, 1.40559], [-59.74066, 1.87596], [-59.7264, 2.27497], [-59.91177, 2.36759], [-59.99733, 2.92312], [-59.79769, 3.37162], [-59.86899, 3.57089], [-59.51963, 3.91951], [-59.73353, 4.20399], [-59.69361, 4.34069]]]]
24315 nameEn: "The Bahamas",
24316 groups: ["029", "003", "419", "019", "UN"],
24318 roadSpeedUnit: "mph",
24319 callingCodes: ["1 242"]
24322 type: "MultiPolygon",
24323 coordinates: [[[[-72.98446, 20.4801], [-71.70065, 25.7637], [-78.91214, 27.76553], [-80.65727, 23.71953], [-72.98446, 20.4801]]]]
24333 groups: ["034", "142", "UN"],
24335 callingCodes: ["975"]
24338 type: "MultiPolygon",
24339 coordinates: [[[[91.6469, 27.76358], [91.5629, 27.84823], [91.48973, 27.93903], [91.46327, 28.0064], [91.25779, 28.07509], [91.20019, 27.98715], [90.69894, 28.07784], [90.58842, 28.02838], [90.13387, 28.19178], [89.79762, 28.23979], [89.59525, 28.16433], [89.12825, 27.62502], [89.0582, 27.60985], [88.97213, 27.51671], [88.95355, 27.4106], [89.00216, 27.32532], [88.96947, 27.30319], [88.93678, 27.33777], [88.91901, 27.32483], [88.74219, 27.144], [88.86984, 27.10937], [88.8714, 26.97488], [88.92301, 26.99286], [88.95807, 26.92668], [89.09554, 26.89089], [89.12825, 26.81661], [89.1926, 26.81329], [89.37913, 26.86224], [89.38319, 26.85963], [89.3901, 26.84225], [89.42349, 26.83727], [89.63369, 26.74402], [89.86124, 26.73307], [90.04535, 26.72422], [90.30402, 26.85098], [90.39271, 26.90704], [90.48504, 26.8594], [90.67715, 26.77215], [91.50067, 26.79223], [91.83181, 26.87318], [92.05523, 26.8692], [92.11863, 26.893], [92.03457, 27.07334], [92.04702, 27.26861], [92.12019, 27.27829], [92.01132, 27.47352], [91.65007, 27.48287], [91.55819, 27.6144], [91.6469, 27.76358]]]]
24347 wikidata: "Q23408",
24348 nameEn: "Bouvet Island",
24350 groups: ["005", "419", "019", "UN"]
24353 type: "MultiPolygon",
24354 coordinates: [[[[4.54042, -54.0949], [2.28941, -54.13089], [3.35353, -55.17558], [4.54042, -54.0949]]]]
24363 nameEn: "Botswana",
24364 groups: ["018", "202", "002", "UN"],
24366 callingCodes: ["267"]
24369 type: "MultiPolygon",
24370 coordinates: [[[[25.26433, -17.79571], [25.16882, -17.78253], [25.05895, -17.84452], [24.95586, -17.79674], [24.73364, -17.89338], [24.71887, -17.9218], [24.6303, -17.9863], [24.57485, -18.07151], [24.40577, -17.95726], [24.19416, -18.01919], [23.61088, -18.4881], [23.29618, -17.99855], [23.0996, -18.00075], [21.45556, -18.31795], [20.99904, -18.31743], [20.99751, -22.00026], [19.99912, -21.99991], [19.99817, -24.76768], [20.02809, -24.78725], [20.03678, -24.81004], [20.29826, -24.94869], [20.64795, -25.47827], [20.86081, -26.14892], [20.61754, -26.4692], [20.63275, -26.78181], [20.68596, -26.9039], [20.87031, -26.80047], [21.13353, -26.86661], [21.37869, -26.82083], [21.69322, -26.86152], [21.7854, -26.79199], [21.77114, -26.69015], [21.83291, -26.65959], [21.90703, -26.66808], [22.06192, -26.61882], [22.21206, -26.3773], [22.41921, -26.23078], [22.56365, -26.19668], [22.70808, -25.99186], [22.86012, -25.50572], [23.03497, -25.29971], [23.47588, -25.29971], [23.9244, -25.64286], [24.18287, -25.62916], [24.36531, -25.773], [24.44703, -25.73021], [24.67319, -25.81749], [24.8946, -25.80723], [25.01718, -25.72507], [25.12266, -25.75931], [25.33076, -25.76616], [25.58543, -25.6343], [25.6643, -25.4491], [25.69661, -25.29284], [25.72702, -25.25503], [25.88571, -24.87802], [25.84295, -24.78661], [25.8515, -24.75727], [26.39409, -24.63468], [26.46346, -24.60358], [26.51667, -24.47219], [26.84165, -24.24885], [26.99749, -23.65486], [27.33768, -23.40917], [27.52393, -23.37952], [27.6066, -23.21894], [27.74154, -23.2137], [27.93539, -23.04941], [27.93729, -22.96194], [28.04752, -22.90243], [28.04562, -22.8394], [28.34874, -22.5694], [28.63287, -22.55887], [28.91889, -22.44299], [29.0151, -22.22907], [29.10881, -22.21202], [29.15268, -22.21399], [29.18974, -22.18599], [29.21955, -22.17771], [29.37703, -22.19581], [29.3533, -22.18363], [29.24648, -22.05967], [29.1974, -22.07472], [29.14501, -22.07275], [29.08495, -22.04867], [29.04108, -22.00563], [29.02191, -21.95665], [29.02191, -21.90647], [29.04023, -21.85864], [29.07763, -21.81877], [28.58114, -21.63455], [28.49942, -21.66634], [28.29416, -21.59037], [28.01669, -21.57624], [27.91407, -21.31621], [27.69171, -21.08409], [27.72972, -20.51735], [27.69361, -20.48531], [27.28865, -20.49873], [27.29831, -20.28935], [27.21278, -20.08244], [26.72246, -19.92707], [26.17227, -19.53709], [25.96226, -19.08152], [25.99837, -19.02943], [25.94326, -18.90362], [25.82353, -18.82808], [25.79217, -18.6355], [25.68859, -18.56165], [25.53465, -18.39041], [25.39972, -18.12691], [25.31799, -18.07091], [25.23909, -17.90832], [25.26433, -17.79571]]]]
24380 groups: ["151", "150", "UN"],
24381 callingCodes: ["375"]
24384 type: "MultiPolygon",
24385 coordinates: [[[[28.15217, 56.16964], [27.97865, 56.11849], [27.63065, 55.89687], [27.61683, 55.78558], [27.3541, 55.8089], [27.27804, 55.78299], [27.1559, 55.85032], [26.97153, 55.8102], [26.87448, 55.7172], [26.76872, 55.67658], [26.71802, 55.70645], [26.64888, 55.70515], [26.63231, 55.67968], [26.63167, 55.57887], [26.55094, 55.5093], [26.5522, 55.40277], [26.44937, 55.34832], [26.5709, 55.32572], [26.6714, 55.33902], [26.80929, 55.31642], [26.83266, 55.30444], [26.835, 55.28182], [26.73017, 55.24226], [26.72983, 55.21788], [26.68075, 55.19787], [26.69243, 55.16718], [26.54753, 55.14181], [26.51481, 55.16051], [26.46249, 55.12814], [26.35121, 55.1525], [26.30628, 55.12536], [26.23202, 55.10439], [26.26941, 55.08032], [26.20397, 54.99729], [26.13386, 54.98924], [26.05907, 54.94631], [25.99129, 54.95705], [25.89462, 54.93438], [25.74122, 54.80108], [25.75977, 54.57252], [25.68045, 54.5321], [25.64813, 54.48704], [25.62203, 54.4656], [25.63371, 54.42075], [25.5376, 54.33158], [25.55425, 54.31591], [25.68513, 54.31727], [25.78553, 54.23327], [25.78563, 54.15747], [25.71084, 54.16704], [25.64875, 54.1259], [25.54724, 54.14925], [25.51452, 54.17799], [25.56823, 54.25212], [25.509, 54.30267], [25.35559, 54.26544], [25.22705, 54.26271], [25.19199, 54.219], [25.0728, 54.13419], [24.991, 54.14241], [24.96894, 54.17589], [24.77131, 54.11091], [24.85311, 54.02862], [24.74279, 53.96663], [24.69185, 53.96543], [24.69652, 54.01901], [24.62275, 54.00217], [24.44411, 53.90076], [24.34128, 53.90076], [24.19638, 53.96405], [23.98837, 53.92554], [23.95098, 53.9613], [23.81309, 53.94205], [23.80543, 53.89558], [23.71726, 53.93379], [23.61677, 53.92691], [23.51284, 53.95052], [23.62004, 53.60942], [23.81995, 53.24131], [23.85657, 53.22923], [23.91393, 53.16469], [23.87548, 53.0831], [23.92184, 53.02079], [23.94689, 52.95919], [23.91805, 52.94016], [23.93763, 52.71332], [23.73615, 52.6149], [23.58296, 52.59868], [23.45112, 52.53774], [23.34141, 52.44845], [23.18196, 52.28812], [23.20071, 52.22848], [23.47859, 52.18215], [23.54314, 52.12148], [23.61, 52.11264], [23.64066, 52.07626], [23.68733, 51.9906], [23.61523, 51.92066], [23.62691, 51.78208], [23.53198, 51.74298], [23.57053, 51.55938], [23.56236, 51.53673], [23.62751, 51.50512], [23.6736, 51.50255], [23.60906, 51.62122], [23.7766, 51.66809], [23.91118, 51.63316], [23.8741, 51.59734], [23.99907, 51.58369], [24.13075, 51.66979], [24.3163, 51.75063], [24.29021, 51.80841], [24.37123, 51.88222], [24.98784, 51.91273], [25.20228, 51.97143], [25.46163, 51.92205], [25.73673, 51.91973], [25.80574, 51.94556], [25.83217, 51.92587], [26.00408, 51.92967], [26.19084, 51.86781], [26.39367, 51.87315], [26.46962, 51.80501], [26.69759, 51.82284], [26.80043, 51.75777], [26.9489, 51.73788], [26.99422, 51.76933], [27.20602, 51.77291], [27.20948, 51.66713], [27.26613, 51.65957], [27.24828, 51.60161], [27.47212, 51.61184], [27.51058, 51.5854], [27.55727, 51.63486], [27.71932, 51.60672], [27.67125, 51.50854], [27.76052, 51.47604], [27.85253, 51.62293], [27.91844, 51.61952], [27.95827, 51.56065], [28.10658, 51.57857], [28.23452, 51.66988], [28.37592, 51.54505], [28.47051, 51.59734], [28.64429, 51.5664], [28.69161, 51.44695], [28.73143, 51.46236], [28.75615, 51.41442], [28.78224, 51.45294], [28.76027, 51.48802], [28.81795, 51.55552], [28.95528, 51.59222], [28.99098, 51.56833], [29.1187, 51.65872], [29.16402, 51.64679], [29.20659, 51.56918], [29.25603, 51.57089], [29.25191, 51.49828], [29.32881, 51.37843], [29.42357, 51.4187], [29.49773, 51.39814], [29.54372, 51.48372], [29.7408, 51.53417], [29.77376, 51.4461], [30.17888, 51.51025], [30.34642, 51.42555], [30.36153, 51.33984], [30.56203, 51.25655], [30.64992, 51.35014], [30.51946, 51.59649], [30.68804, 51.82806], [30.76443, 51.89739], [30.90897, 52.00699], [30.95589, 52.07775], [31.13332, 52.1004], [31.25142, 52.04131], [31.38326, 52.12991], [31.7822, 52.11406], [31.77877, 52.18636], [31.6895, 52.1973], [31.70735, 52.26711], [31.57971, 52.32146], [31.62084, 52.33849], [31.61397, 52.48843], [31.56316, 52.51518], [31.63869, 52.55361], [31.50406, 52.69707], [31.57277, 52.71613], [31.592, 52.79011], [31.35667, 52.97854], [31.24147, 53.031], [31.32283, 53.04101], [31.33519, 53.08805], [31.3915, 53.09712], [31.36403, 53.13504], [31.40523, 53.21406], [31.56316, 53.19432], [31.62496, 53.22886], [31.787, 53.18033], [31.82373, 53.10042], [32.15368, 53.07594], [32.40773, 53.18856], [32.51725, 53.28431], [32.73257, 53.33494], [32.74968, 53.45597], [32.47777, 53.5548], [32.40499, 53.6656], [32.50112, 53.68594], [32.45717, 53.74039], [32.36663, 53.7166], [32.12621, 53.81586], [31.89137, 53.78099], [31.77028, 53.80015], [31.85019, 53.91801], [31.88744, 54.03653], [31.89599, 54.0837], [31.57002, 54.14535], [31.30791, 54.25315], [31.3177, 54.34067], [31.22945, 54.46585], [31.08543, 54.50361], [31.21399, 54.63113], [31.19339, 54.66947], [30.99187, 54.67046], [30.98226, 54.68872], [31.0262, 54.70698], [30.97127, 54.71967], [30.95479, 54.74346], [30.75165, 54.80699], [30.8264, 54.90062], [30.81759, 54.94064], [30.93144, 54.9585], [30.95754, 54.98609], [30.9081, 55.02232], [30.94243, 55.03964], [31.00972, 55.02783], [31.02071, 55.06167], [30.97369, 55.17134], [30.87944, 55.28223], [30.81946, 55.27931], [30.8257, 55.3313], [30.93144, 55.3914], [30.90123, 55.46621], [30.95204, 55.50667], [30.93419, 55.6185], [30.86003, 55.63169], [30.7845, 55.58514], [30.72957, 55.66268], [30.67464, 55.64176], [30.63344, 55.73079], [30.51037, 55.76568], [30.51346, 55.78982], [30.48257, 55.81066], [30.30987, 55.83592], [30.27776, 55.86819], [30.12136, 55.8358], [29.97975, 55.87281], [29.80672, 55.79569], [29.61446, 55.77716], [29.51283, 55.70294], [29.3604, 55.75862], [29.44692, 55.95978], [29.21717, 55.98971], [29.08299, 56.03427], [28.73418, 55.97131], [28.63668, 56.07262], [28.68337, 56.10173], [28.5529, 56.11705], [28.43068, 56.09407], [28.37987, 56.11399], [28.36888, 56.05805], [28.30571, 56.06035], [28.15217, 56.16964]]]]
24395 groups: ["013", "003", "419", "019", "UN"],
24396 roadSpeedUnit: "mph",
24397 callingCodes: ["501"]
24400 type: "MultiPolygon",
24401 coordinates: [[[[-88.3268, 18.49048], [-88.48242, 18.49164], [-88.71505, 18.0707], [-88.8716, 17.89535], [-89.03839, 18.0067], [-89.15105, 17.95104], [-89.14985, 17.81563], [-89.15025, 17.04813], [-89.22683, 15.88619], [-89.17418, 15.90898], [-89.02415, 15.9063], [-88.95358, 15.88698], [-88.40779, 16.09624], [-86.92368, 17.61462], [-87.84815, 18.18511], [-87.85693, 18.18266], [-87.86657, 18.19971], [-87.87604, 18.18313], [-87.90671, 18.15213], [-88.03165, 18.16657], [-88.03238, 18.41778], [-88.26593, 18.47617], [-88.29909, 18.47591], [-88.3268, 18.49048]]]]
24411 groups: ["021", "003", "019", "UN"],
24412 callingCodes: ["1"]
24415 type: "MultiPolygon",
24416 coordinates: [[[[-67.20349, 45.1722], [-67.19603, 45.16771], [-67.15965, 45.16179], [-67.11316, 45.11176], [-67.0216, 44.95333], [-66.96824, 44.90965], [-66.98249, 44.87071], [-66.96824, 44.83078], [-66.93432, 44.82597], [-67.16117, 44.20069], [-61.98255, 37.34815], [-56.27503, 47.39728], [-53.12387, 41.40385], [-46.37635, 57.3249], [-77.52957, 77.23408], [-68.21821, 80.48551], [-49.33696, 84.57952], [-140.97446, 84.39275], [-141.00116, 60.30648], [-140.5227, 60.22077], [-140.45648, 60.30919], [-139.98024, 60.18027], [-139.68991, 60.33693], [-139.05831, 60.35205], [-139.20603, 60.08896], [-139.05365, 59.99655], [-138.71149, 59.90728], [-138.62145, 59.76431], [-137.60623, 59.24465], [-137.4925, 58.89415], [-136.82619, 59.16198], [-136.52365, 59.16752], [-136.47323, 59.46617], [-136.33727, 59.44466], [-136.22381, 59.55526], [-136.31566, 59.59083], [-135.48007, 59.79937], [-135.03069, 59.56208], [-135.00267, 59.28745], [-134.7047, 59.2458], [-134.55699, 59.1297], [-134.48059, 59.13231], [-134.27175, 58.8634], [-133.84645, 58.73543], [-133.38523, 58.42773], [-131.8271, 56.62247], [-130.77769, 56.36185], [-130.33965, 56.10849], [-130.10173, 56.12178], [-130.00093, 56.00325], [-130.00857, 55.91344], [-130.15373, 55.74895], [-129.97513, 55.28029], [-130.08035, 55.21556], [-130.18765, 55.07744], [-130.27203, 54.97174], [-130.44184, 54.85377], [-130.64499, 54.76912], [-130.61931, 54.70835], [-133.92876, 54.62289], [-133.36909, 48.51151], [-125.03842, 48.53282], [-123.50039, 48.21223], [-123.15614, 48.35395], [-123.26565, 48.6959], [-123.0093, 48.76586], [-123.0093, 48.83186], [-123.32163, 49.00419], [-95.15355, 48.9996], [-95.15357, 49.384], [-95.12903, 49.37056], [-95.05825, 49.35311], [-95.01419, 49.35647], [-94.99532, 49.36579], [-94.95681, 49.37035], [-94.85381, 49.32492], [-94.8159, 49.32299], [-94.82487, 49.29483], [-94.77355, 49.11998], [-94.75017, 49.09931], [-94.687, 48.84077], [-94.70087, 48.8339], [-94.70486, 48.82365], [-94.69669, 48.80918], [-94.69335, 48.77883], [-94.58903, 48.71803], [-94.54885, 48.71543], [-94.53826, 48.70216], [-94.44258, 48.69223], [-94.4174, 48.71049], [-94.27153, 48.70232], [-94.25172, 48.68404], [-94.25104, 48.65729], [-94.23215, 48.65202], [-93.85769, 48.63284], [-93.83288, 48.62745], [-93.80676, 48.58232], [-93.80939, 48.52439], [-93.79267, 48.51631], [-93.66382, 48.51845], [-93.47022, 48.54357], [-93.44472, 48.59147], [-93.40693, 48.60948], [-93.39758, 48.60364], [-93.3712, 48.60599], [-93.33946, 48.62787], [-93.25391, 48.64266], [-92.94973, 48.60866], [-92.7287, 48.54005], [-92.6342, 48.54133], [-92.62747, 48.50278], [-92.69927, 48.49573], [-92.71323, 48.46081], [-92.65606, 48.43471], [-92.50712, 48.44921], [-92.45588, 48.40624], [-92.48147, 48.36609], [-92.37185, 48.22259], [-92.27167, 48.25046], [-92.30939, 48.31251], [-92.26662, 48.35651], [-92.202, 48.35252], [-92.14732, 48.36578], [-92.05339, 48.35958], [-91.98929, 48.25409], [-91.86125, 48.21278], [-91.71231, 48.19875], [-91.70451, 48.11805], [-91.55649, 48.10611], [-91.58025, 48.04339], [-91.45829, 48.07454], [-91.43248, 48.04912], [-91.25025, 48.08522], [-91.08016, 48.18096], [-90.87588, 48.2484], [-90.75045, 48.09143], [-90.56444, 48.12184], [-90.56312, 48.09488], [-90.07418, 48.11043], [-89.89974, 47.98109], [-89.77248, 48.02607], [-89.57972, 48.00023], [-89.48837, 48.01412], [-88.37033, 48.30586], [-84.85871, 46.88881], [-84.55635, 46.45974], [-84.47607, 46.45225], [-84.4481, 46.48972], [-84.42101, 46.49853], [-84.34174, 46.50683], [-84.29893, 46.49127], [-84.26351, 46.49508], [-84.2264, 46.53337], [-84.1945, 46.54061], [-84.17723, 46.52753], [-84.12885, 46.53068], [-84.11196, 46.50248], [-84.13451, 46.39218], [-84.11254, 46.32329], [-84.11615, 46.2681], [-84.09756, 46.25512], [-84.1096, 46.23987], [-83.95399, 46.05634], [-83.90453, 46.05922], [-83.83329, 46.12169], [-83.57017, 46.105], [-83.43746, 45.99749], [-83.59589, 45.82131], [-82.48419, 45.30225], [-82.42469, 42.992], [-82.4146, 42.97626], [-82.4253, 42.95423], [-82.45331, 42.93139], [-82.4826, 42.8068], [-82.46613, 42.76615], [-82.51063, 42.66025], [-82.51858, 42.611], [-82.57583, 42.5718], [-82.58873, 42.54984], [-82.64242, 42.55594], [-82.82964, 42.37355], [-83.02253, 42.33045], [-83.07837, 42.30978], [-83.09837, 42.28877], [-83.12724, 42.2376], [-83.14962, 42.04089], [-83.11184, 41.95671], [-82.67862, 41.67615], [-78.93684, 42.82887], [-78.90712, 42.89733], [-78.90905, 42.93022], [-78.93224, 42.95229], [-78.96312, 42.95509], [-78.98126, 42.97], [-79.02074, 42.98444], [-79.02424, 43.01983], [-78.99941, 43.05612], [-79.01055, 43.06659], [-79.07486, 43.07845], [-79.05671, 43.10937], [-79.06881, 43.12029], [-79.0427, 43.13934], [-79.04652, 43.16396], [-79.05384, 43.17418], [-79.05002, 43.20133], [-79.05544, 43.21224], [-79.05512, 43.25375], [-79.06921, 43.26183], [-79.25796, 43.54052], [-76.79706, 43.63099], [-76.43859, 44.09393], [-76.35324, 44.13493], [-76.31222, 44.19894], [-76.244, 44.19643], [-76.1664, 44.23051], [-76.16285, 44.28262], [-76.00018, 44.34896], [-75.95947, 44.34463], [-75.8217, 44.43176], [-75.76813, 44.51537], [-75.41441, 44.76614], [-75.2193, 44.87821], [-75.01363, 44.95608], [-74.99101, 44.98051], [-74.8447, 45.00606], [-74.66689, 45.00646], [-74.32699, 44.99029], [-73.35025, 45.00942], [-71.50067, 45.01357], [-71.48735, 45.07784], [-71.42778, 45.12624], [-71.40364, 45.21382], [-71.44252, 45.2361], [-71.37133, 45.24624], [-71.29371, 45.29996], [-71.22338, 45.25184], [-71.19723, 45.25438], [-71.14568, 45.24128], [-71.08364, 45.30623], [-71.01866, 45.31573], [-71.0107, 45.34819], [-70.95193, 45.33895], [-70.91169, 45.29849], [-70.89864, 45.2398], [-70.84816, 45.22698], [-70.80236, 45.37444], [-70.82638, 45.39828], [-70.78372, 45.43269], [-70.65383, 45.37592], [-70.62518, 45.42286], [-70.72651, 45.49771], [-70.68516, 45.56964], [-70.54019, 45.67291], [-70.38934, 45.73215], [-70.41523, 45.79497], [-70.25976, 45.89675], [-70.24694, 45.95138], [-70.31025, 45.96424], [-70.23855, 46.1453], [-70.29078, 46.18832], [-70.18547, 46.35357], [-70.05812, 46.41768], [-69.99966, 46.69543], [-69.22119, 47.46461], [-69.05148, 47.42012], [-69.05073, 47.30076], [-69.05039, 47.2456], [-68.89222, 47.1807], [-68.70125, 47.24399], [-68.60575, 47.24659], [-68.57914, 47.28431], [-68.38332, 47.28723], [-68.37458, 47.35851], [-68.23244, 47.35712], [-67.94843, 47.1925], [-67.87993, 47.10377], [-67.78578, 47.06473], [-67.78111, 45.9392], [-67.75196, 45.91814], [-67.80961, 45.87531], [-67.75654, 45.82324], [-67.80653, 45.80022], [-67.80705, 45.69528], [-67.6049, 45.60725], [-67.43815, 45.59162], [-67.42144, 45.50584], [-67.50578, 45.48971], [-67.42394, 45.37969], [-67.48201, 45.27351], [-67.34927, 45.122], [-67.29754, 45.14865], [-67.29748, 45.18173], [-67.27039, 45.1934], [-67.22751, 45.16344], [-67.20349, 45.1722]]]]
24424 wikidata: "Q36004",
24425 nameEn: "Cocos (Keeling) Islands",
24427 groups: ["053", "009", "UN"],
24429 callingCodes: ["61"]
24432 type: "MultiPolygon",
24433 coordinates: [[[[96.61846, -10.82438], [96.02343, -12.68334], [97.93979, -12.33309], [96.61846, -10.82438]]]]
24442 nameEn: "Democratic Republic of the Congo",
24444 groups: ["017", "202", "002", "UN"],
24445 callingCodes: ["243"]
24448 type: "MultiPolygon",
24449 coordinates: [[[[27.44012, 5.07349], [27.09575, 5.22305], [26.93064, 5.13535], [26.85579, 5.03887], [26.74572, 5.10685], [26.48595, 5.04984], [26.13371, 5.25594], [25.86073, 5.19455], [25.53271, 5.37431], [25.34558, 5.29101], [25.31256, 5.03668], [24.71816, 4.90509], [24.46719, 5.0915], [23.38847, 4.60013], [22.94817, 4.82392], [22.89094, 4.79321], [22.84691, 4.69887], [22.78526, 4.71423], [22.6928, 4.47285], [22.60915, 4.48821], [22.5431, 4.22041], [22.45504, 4.13039], [22.27682, 4.11347], [22.10721, 4.20723], [21.6405, 4.317], [21.55904, 4.25553], [21.25744, 4.33676], [21.21341, 4.29285], [21.11214, 4.33895], [21.08793, 4.39603], [20.90383, 4.44877], [20.60184, 4.42394], [18.62755, 3.47564], [18.63857, 3.19342], [18.10683, 2.26876], [18.08034, 1.58553], [17.85887, 1.04327], [17.86989, 0.58873], [17.95255, 0.48128], [17.93877, 0.32424], [17.81204, 0.23884], [17.66051, -0.26535], [17.72112, -0.52707], [17.32438, -0.99265], [16.97999, -1.12762], [16.70724, -1.45815], [16.50336, -1.8795], [16.16173, -2.16586], [16.22785, -2.59528], [16.1755, -3.25014], [16.21407, -3.2969], [15.89448, -3.9513], [15.53081, -4.042], [15.48121, -4.22062], [15.41785, -4.28381], [15.32693, -4.27282], [15.25411, -4.31121], [15.1978, -4.32388], [14.83101, -4.80838], [14.67948, -4.92093], [14.5059, -4.84956], [14.41499, -4.8825], [14.37366, -4.56125], [14.47284, -4.42941], [14.3957, -4.36623], [14.40672, -4.28381], [13.9108, -4.50906], [13.81162, -4.41842], [13.71794, -4.44864], [13.70417, -4.72601], [13.50305, -4.77818], [13.41764, -4.89897], [13.11182, -4.5942], [13.09648, -4.63739], [13.11195, -4.67745], [12.8733, -4.74346], [12.70868, -4.95505], [12.63465, -4.94632], [12.60251, -5.01715], [12.46297, -5.09408], [12.49815, -5.14058], [12.51589, -5.1332], [12.53586, -5.14658], [12.53599, -5.1618], [12.52301, -5.17481], [12.52318, -5.74353], [12.26557, -5.74031], [12.20376, -5.76338], [11.95767, -5.94705], [12.42245, -6.07585], [13.04371, -5.87078], [16.55507, -5.85631], [16.96282, -7.21787], [17.5828, -8.13784], [18.33635, -8.00126], [19.33698, -7.99743], [19.5469, -7.00195], [20.30218, -6.98955], [20.31846, -6.91953], [20.61689, -6.90876], [20.56263, -7.28566], [21.79824, -7.29628], [21.84856, -9.59871], [22.19039, -9.94628], [22.32604, -10.76291], [22.17954, -10.85884], [22.25951, -11.24911], [22.54205, -11.05784], [23.16602, -11.10577], [23.45631, -10.946], [23.86868, -11.02856], [24.00027, -10.89356], [24.34528, -11.06816], [24.42612, -11.44975], [25.34069, -11.19707], [25.33058, -11.65767], [26.01777, -11.91488], [26.88687, -12.01868], [27.04351, -11.61312], [27.22541, -11.60323], [27.21025, -11.76157], [27.59932, -12.22123], [28.33199, -12.41375], [29.01918, -13.41353], [29.60531, -13.21685], [29.65078, -13.41844], [29.81551, -13.44683], [29.8139, -12.14898], [29.48404, -12.23604], [29.4992, -12.43843], [29.18592, -12.37921], [28.48357, -11.87532], [28.37241, -11.57848], [28.65032, -10.65133], [28.62795, -9.92942], [28.68532, -9.78], [28.56208, -9.49122], [28.51627, -9.44726], [28.52636, -9.35379], [28.36562, -9.30091], [28.38526, -9.23393], [28.9711, -8.66935], [28.88917, -8.4831], [30.79243, -8.27382], [30.2567, -7.14121], [29.52552, -6.2731], [29.43673, -4.44845], [29.23708, -3.75856], [29.21463, -3.3514], [29.25633, -3.05471], [29.17258, -2.99385], [29.16037, -2.95457], [29.09797, -2.91935], [29.09119, -2.87871], [29.0505, -2.81774], [29.00404, -2.81978], [29.00167, -2.78523], [29.04081, -2.7416], [29.00357, -2.70596], [28.94346, -2.69124], [28.89793, -2.66111], [28.90226, -2.62385], [28.89288, -2.55848], [28.87943, -2.55165], [28.86193, -2.53185], [28.86209, -2.5231], [28.87497, -2.50887], [28.88846, -2.50493], [28.89342, -2.49017], [28.89132, -2.47557], [28.86846, -2.44866], [28.86826, -2.41888], [28.89601, -2.37321], [28.95642, -2.37321], [29.00051, -2.29001], [29.105, -2.27043], [29.17562, -2.12278], [29.11847, -1.90576], [29.24458, -1.69663], [29.24323, -1.66826], [29.36322, -1.50887], [29.45038, -1.5054], [29.53062, -1.40499], [29.59061, -1.39016], [29.58388, -0.89821], [29.63006, -0.8997], [29.62708, -0.71055], [29.67176, -0.55714], [29.67474, -0.47969], [29.65091, -0.46777], [29.72687, -0.08051], [29.7224, 0.07291], [29.77454, 0.16675], [29.81922, 0.16824], [29.87284, 0.39166], [29.97413, 0.52124], [29.95477, 0.64486], [29.98307, 0.84295], [30.1484, 0.89805], [30.22139, 0.99635], [30.24671, 1.14974], [30.48503, 1.21675], [31.30127, 2.11006], [31.28042, 2.17853], [31.20148, 2.2217], [31.1985, 2.29462], [31.12104, 2.27676], [31.07934, 2.30207], [31.06593, 2.35862], [30.96911, 2.41071], [30.91102, 2.33332], [30.83059, 2.42559], [30.74271, 2.43601], [30.75612, 2.5863], [30.8857, 2.83923], [30.8574, 2.9508], [30.77101, 3.04897], [30.84251, 3.26908], [30.93486, 3.40737], [30.94081, 3.50847], [30.85153, 3.48867], [30.85997, 3.5743], [30.80713, 3.60506], [30.78512, 3.67097], [30.56277, 3.62703], [30.57378, 3.74567], [30.55396, 3.84451], [30.47691, 3.83353], [30.27658, 3.95653], [30.22374, 3.93896], [30.1621, 4.10586], [30.06964, 4.13221], [29.79666, 4.37809], [29.82087, 4.56246], [29.49726, 4.7007], [29.43341, 4.50101], [29.22207, 4.34297], [29.03054, 4.48784], [28.8126, 4.48784], [28.6651, 4.42638], [28.20719, 4.35614], [27.79551, 4.59976], [27.76469, 4.79284], [27.65462, 4.89375], [27.56656, 4.89375], [27.44012, 5.07349]]]]
24458 nameEn: "Central African Republic",
24459 groups: ["017", "202", "002", "UN"],
24460 callingCodes: ["236"]
24463 type: "MultiPolygon",
24464 coordinates: [[[[22.87758, 10.91915], [22.45889, 11.00246], [21.72139, 10.64136], [21.71479, 10.29932], [21.63553, 10.217], [21.52766, 10.2105], [21.34934, 9.95907], [21.26348, 9.97642], [20.82979, 9.44696], [20.36748, 9.11019], [19.06421, 9.00367], [18.86388, 8.87971], [19.11044, 8.68172], [18.79783, 8.25929], [18.67455, 8.22226], [18.62612, 8.14163], [18.64153, 8.08714], [18.6085, 8.05009], [18.02731, 8.01085], [17.93926, 7.95853], [17.67288, 7.98905], [16.8143, 7.53971], [16.6668, 7.67281], [16.658, 7.75353], [16.59415, 7.76444], [16.58315, 7.88657], [16.41583, 7.77971], [16.40703, 7.68809], [15.79942, 7.44149], [15.73118, 7.52006], [15.49743, 7.52179], [15.23397, 7.25135], [15.04717, 6.77085], [14.96311, 6.75693], [14.79966, 6.39043], [14.80122, 6.34866], [14.74206, 6.26356], [14.56149, 6.18928], [14.43073, 6.08867], [14.42917, 6.00508], [14.49455, 5.91683], [14.60974, 5.91838], [14.62375, 5.70466], [14.58951, 5.59777], [14.62531, 5.51411], [14.52724, 5.28319], [14.57083, 5.23979], [14.65489, 5.21343], [14.73383, 4.6135], [15.00825, 4.41458], [15.08609, 4.30282], [15.10644, 4.1362], [15.17482, 4.05131], [15.07686, 4.01805], [15.73522, 3.24348], [15.77725, 3.26835], [16.05449, 3.02306], [16.08252, 2.45708], [16.19357, 2.21537], [16.50126, 2.84739], [16.46701, 2.92512], [16.57598, 3.47999], [16.68283, 3.54257], [17.01746, 3.55136], [17.35649, 3.63045], [17.46876, 3.70515], [17.60966, 3.63705], [17.83421, 3.61068], [17.85842, 3.53378], [18.05656, 3.56893], [18.14902, 3.54476], [18.17323, 3.47665], [18.24148, 3.50302], [18.2723, 3.57992], [18.39558, 3.58212], [18.49245, 3.63924], [18.58711, 3.49423], [18.62755, 3.47564], [20.60184, 4.42394], [20.90383, 4.44877], [21.08793, 4.39603], [21.11214, 4.33895], [21.21341, 4.29285], [21.25744, 4.33676], [21.55904, 4.25553], [21.6405, 4.317], [22.10721, 4.20723], [22.27682, 4.11347], [22.45504, 4.13039], [22.5431, 4.22041], [22.60915, 4.48821], [22.6928, 4.47285], [22.78526, 4.71423], [22.84691, 4.69887], [22.89094, 4.79321], [22.94817, 4.82392], [23.38847, 4.60013], [24.46719, 5.0915], [24.71816, 4.90509], [25.31256, 5.03668], [25.34558, 5.29101], [25.53271, 5.37431], [25.86073, 5.19455], [26.13371, 5.25594], [26.48595, 5.04984], [26.74572, 5.10685], [26.85579, 5.03887], [26.93064, 5.13535], [27.09575, 5.22305], [27.44012, 5.07349], [27.26886, 5.25876], [27.23017, 5.37167], [27.28621, 5.56382], [27.22705, 5.62889], [27.22705, 5.71254], [26.51721, 6.09655], [26.58259, 6.1987], [26.32729, 6.36272], [26.38022, 6.63493], [25.90076, 7.09549], [25.37461, 7.33024], [25.35281, 7.42595], [25.20337, 7.50312], [25.20649, 7.61115], [25.29214, 7.66675], [25.25319, 7.8487], [24.98855, 7.96588], [24.85156, 8.16933], [24.35965, 8.26177], [24.13238, 8.36959], [24.25691, 8.69288], [23.51905, 8.71749], [23.59065, 8.99743], [23.44744, 8.99128], [23.4848, 9.16959], [23.56263, 9.19418], [23.64358, 9.28637], [23.64981, 9.44303], [23.62179, 9.53823], [23.69155, 9.67566], [23.67164, 9.86923], [23.3128, 10.45214], [23.02221, 10.69235], [22.87758, 10.91915]]]]
24473 nameEn: "Republic of the Congo",
24474 groups: ["017", "202", "002", "UN"],
24475 callingCodes: ["242"]
24478 type: "MultiPolygon",
24479 coordinates: [[[[18.62755, 3.47564], [18.58711, 3.49423], [18.49245, 3.63924], [18.39558, 3.58212], [18.2723, 3.57992], [18.24148, 3.50302], [18.17323, 3.47665], [18.14902, 3.54476], [18.05656, 3.56893], [17.85842, 3.53378], [17.83421, 3.61068], [17.60966, 3.63705], [17.46876, 3.70515], [17.35649, 3.63045], [17.01746, 3.55136], [16.68283, 3.54257], [16.57598, 3.47999], [16.46701, 2.92512], [16.50126, 2.84739], [16.19357, 2.21537], [16.15568, 2.18955], [16.08563, 2.19733], [16.05294, 1.9811], [16.14634, 1.70259], [16.02647, 1.65591], [16.02959, 1.76483], [15.48942, 1.98265], [15.34776, 1.91264], [15.22634, 2.03243], [15.00996, 1.98887], [14.61145, 2.17866], [13.29457, 2.16106], [13.13461, 1.57238], [13.25447, 1.32339], [13.15519, 1.23368], [13.89582, 1.4261], [14.25186, 1.39842], [14.48179, 0.9152], [14.26066, 0.57255], [14.10909, 0.58563], [13.88648, 0.26652], [13.90632, -0.2287], [14.06862, -0.20826], [14.2165, -0.38261], [14.41887, -0.44799], [14.52569, -0.57818], [14.41838, -1.89412], [14.25932, -1.97624], [14.23518, -2.15671], [14.16202, -2.23916], [14.23829, -2.33715], [14.10442, -2.49268], [13.85846, -2.46935], [13.92073, -2.35581], [13.75884, -2.09293], [13.47977, -2.43224], [13.02759, -2.33098], [12.82172, -1.91091], [12.61312, -1.8129], [12.44656, -1.92025], [12.47925, -2.32626], [12.04895, -2.41704], [11.96866, -2.33559], [11.74605, -2.39936], [11.57637, -2.33379], [11.64487, -2.61865], [11.5359, -2.85654], [11.64798, -2.81146], [11.80365, -3.00424], [11.70558, -3.0773], [11.70227, -3.17465], [11.96554, -3.30267], [11.8318, -3.5812], [11.92719, -3.62768], [11.87083, -3.71571], [11.68608, -3.68942], [11.57949, -3.52798], [11.48764, -3.51089], [11.22301, -3.69888], [11.12647, -3.94169], [10.75913, -4.39519], [11.50888, -5.33417], [12.00924, -5.02627], [12.16068, -4.90089], [12.20901, -4.75642], [12.25587, -4.79437], [12.32324, -4.78415], [12.40964, -4.60609], [12.64835, -4.55937], [12.76844, -4.38709], [12.87096, -4.40315], [12.91489, -4.47907], [13.09648, -4.63739], [13.11182, -4.5942], [13.41764, -4.89897], [13.50305, -4.77818], [13.70417, -4.72601], [13.71794, -4.44864], [13.81162, -4.41842], [13.9108, -4.50906], [14.40672, -4.28381], [14.3957, -4.36623], [14.47284, -4.42941], [14.37366, -4.56125], [14.41499, -4.8825], [14.5059, -4.84956], [14.67948, -4.92093], [14.83101, -4.80838], [15.1978, -4.32388], [15.25411, -4.31121], [15.32693, -4.27282], [15.41785, -4.28381], [15.48121, -4.22062], [15.53081, -4.042], [15.89448, -3.9513], [16.21407, -3.2969], [16.1755, -3.25014], [16.22785, -2.59528], [16.16173, -2.16586], [16.50336, -1.8795], [16.70724, -1.45815], [16.97999, -1.12762], [17.32438, -0.99265], [17.72112, -0.52707], [17.66051, -0.26535], [17.81204, 0.23884], [17.93877, 0.32424], [17.95255, 0.48128], [17.86989, 0.58873], [17.85887, 1.04327], [18.08034, 1.58553], [18.10683, 2.26876], [18.63857, 3.19342], [18.62755, 3.47564]]]]
24488 nameEn: "Switzerland",
24489 groups: ["155", "150", "UN"],
24490 callingCodes: ["41"]
24493 type: "MultiPolygon",
24494 coordinates: [[[[8.72809, 47.69282], [8.72617, 47.69651], [8.73671, 47.7169], [8.70543, 47.73121], [8.74251, 47.75168], [8.71778, 47.76571], [8.68985, 47.75686], [8.68022, 47.78599], [8.65292, 47.80066], [8.64425, 47.76398], [8.62408, 47.7626], [8.61657, 47.79998], [8.56415, 47.80633], [8.56814, 47.78001], [8.48868, 47.77215], [8.45771, 47.7493], [8.44807, 47.72426], [8.40569, 47.69855], [8.4211, 47.68407], [8.40473, 47.67499], [8.41346, 47.66676], [8.42264, 47.66667], [8.44711, 47.65379], [8.4667, 47.65747], [8.46605, 47.64103], [8.49656, 47.64709], [8.5322, 47.64687], [8.52801, 47.66059], [8.56141, 47.67088], [8.57683, 47.66158], [8.6052, 47.67258], [8.61113, 47.66332], [8.62884, 47.65098], [8.62049, 47.63757], [8.60412, 47.63735], [8.61471, 47.64514], [8.60701, 47.65271], [8.59545, 47.64298], [8.60348, 47.61204], [8.57586, 47.59537], [8.55756, 47.62394], [8.51686, 47.63476], [8.50747, 47.61897], [8.45578, 47.60121], [8.46637, 47.58389], [8.48949, 47.588], [8.49431, 47.58107], [8.43235, 47.56617], [8.39477, 47.57826], [8.38273, 47.56608], [8.32735, 47.57133], [8.30277, 47.58607], [8.29524, 47.5919], [8.29722, 47.60603], [8.2824, 47.61225], [8.26313, 47.6103], [8.25863, 47.61571], [8.23809, 47.61204], [8.22577, 47.60385], [8.22011, 47.6181], [8.20617, 47.62141], [8.19378, 47.61636], [8.1652, 47.5945], [8.14947, 47.59558], [8.13823, 47.59147], [8.13662, 47.58432], [8.11543, 47.5841], [8.10395, 47.57918], [8.10002, 47.56504], [8.08557, 47.55768], [8.06663, 47.56374], [8.04383, 47.55443], [8.02136, 47.55096], [8.00113, 47.55616], [7.97581, 47.55493], [7.95682, 47.55789], [7.94494, 47.54511], [7.91251, 47.55031], [7.90673, 47.57674], [7.88664, 47.58854], [7.84412, 47.5841], [7.81901, 47.58798], [7.79486, 47.55691], [7.75261, 47.54599], [7.71961, 47.54219], [7.69642, 47.53297], [7.68101, 47.53232], [7.6656, 47.53752], [7.66174, 47.54554], [7.65083, 47.54662], [7.63338, 47.56256], [7.67655, 47.56435], [7.68904, 47.57133], [7.67115, 47.5871], [7.68486, 47.59601], [7.69385, 47.60099], [7.68229, 47.59905], [7.67395, 47.59212], [7.64599, 47.59695], [7.64213, 47.5944], [7.64309, 47.59151], [7.61929, 47.57683], [7.60459, 47.57869], [7.60523, 47.58519], [7.58945, 47.59017], [7.58386, 47.57536], [7.56684, 47.57785], [7.56548, 47.57617], [7.55689, 47.57232], [7.55652, 47.56779], [7.53634, 47.55553], [7.52831, 47.55347], [7.51723, 47.54578], [7.50873, 47.54546], [7.49691, 47.53821], [7.50588, 47.52856], [7.51904, 47.53515], [7.53199, 47.5284], [7.5229, 47.51644], [7.49804, 47.51798], [7.51076, 47.49651], [7.47534, 47.47932], [7.43356, 47.49712], [7.42923, 47.48628], [7.4583, 47.47216], [7.4462, 47.46264], [7.43088, 47.45846], [7.40308, 47.43638], [7.35603, 47.43432], [7.33526, 47.44186], [7.24669, 47.4205], [7.17026, 47.44312], [7.19583, 47.49455], [7.16249, 47.49025], [7.12781, 47.50371], [7.07425, 47.48863], [7.0231, 47.50522], [6.98425, 47.49432], [7.0024, 47.45264], [6.93953, 47.43388], [6.93744, 47.40714], [6.88542, 47.37262], [6.87959, 47.35335], [7.03125, 47.36996], [7.0564, 47.35134], [7.05305, 47.33304], [6.94316, 47.28747], [6.95108, 47.26428], [6.9508, 47.24338], [6.8489, 47.15933], [6.76788, 47.1208], [6.68823, 47.06616], [6.71531, 47.0494], [6.43341, 46.92703], [6.46456, 46.88865], [6.43216, 46.80336], [6.45209, 46.77502], [6.38351, 46.73171], [6.27135, 46.68251], [6.11084, 46.57649], [6.1567, 46.54402], [6.07269, 46.46244], [6.08427, 46.44305], [6.06407, 46.41676], [6.09926, 46.40768], [6.15016, 46.3778], [6.15985, 46.37721], [6.16987, 46.36759], [6.15738, 46.3491], [6.13876, 46.33844], [6.1198, 46.31157], [6.11697, 46.29547], [6.1013, 46.28512], [6.11926, 46.2634], [6.12446, 46.25059], [6.10071, 46.23772], [6.08563, 46.24651], [6.07072, 46.24085], [6.0633, 46.24583], [6.05029, 46.23518], [6.04602, 46.23127], [6.03342, 46.2383], [6.02461, 46.23313], [5.97542, 46.21525], [5.96515, 46.19638], [5.99573, 46.18587], [5.98846, 46.17046], [5.98188, 46.17392], [5.97508, 46.15863], [5.9641, 46.14412], [5.95781, 46.12925], [5.97893, 46.13303], [5.9871, 46.14499], [6.01791, 46.14228], [6.03614, 46.13712], [6.04564, 46.14031], [6.05203, 46.15191], [6.07491, 46.14879], [6.09199, 46.15191], [6.09926, 46.14373], [6.13397, 46.1406], [6.15305, 46.15194], [6.18116, 46.16187], [6.18871, 46.16644], [6.18707, 46.17999], [6.19552, 46.18401], [6.19807, 46.18369], [6.20539, 46.19163], [6.21114, 46.1927], [6.21273, 46.19409], [6.21603, 46.19507], [6.21844, 46.19837], [6.22222, 46.19888], [6.22175, 46.20045], [6.23544, 46.20714], [6.23913, 46.20511], [6.24821, 46.20531], [6.26007, 46.21165], [6.27694, 46.21566], [6.29663, 46.22688], [6.31041, 46.24417], [6.29474, 46.26221], [6.26749, 46.24745], [6.24952, 46.26255], [6.23775, 46.27822], [6.25137, 46.29014], [6.24826, 46.30175], [6.21981, 46.31304], [6.25432, 46.3632], [6.53358, 46.45431], [6.82312, 46.42661], [6.8024, 46.39171], [6.77152, 46.34784], [6.86052, 46.28512], [6.78968, 46.14058], [6.89321, 46.12548], [6.87868, 46.03855], [6.93862, 46.06502], [7.00946, 45.9944], [7.04151, 45.92435], [7.10685, 45.85653], [7.56343, 45.97421], [7.85949, 45.91485], [7.9049, 45.99945], [7.98881, 45.99867], [8.02906, 46.10331], [8.11383, 46.11577], [8.16866, 46.17817], [8.08814, 46.26692], [8.31162, 46.38044], [8.30648, 46.41587], [8.42464, 46.46367], [8.46317, 46.43712], [8.45032, 46.26869], [8.62242, 46.12112], [8.75697, 46.10395], [8.80778, 46.10085], [8.85617, 46.0748], [8.79414, 46.00913], [8.78585, 45.98973], [8.79362, 45.99207], [8.8319, 45.9879], [8.85121, 45.97239], [8.86688, 45.96135], [8.88904, 45.95465], [8.93649, 45.86775], [8.94372, 45.86587], [8.93504, 45.86245], [8.91129, 45.8388], [8.94737, 45.84285], [8.9621, 45.83707], [8.99663, 45.83466], [9.00324, 45.82055], [9.0298, 45.82127], [9.03279, 45.82865], [9.03793, 45.83548], [9.03505, 45.83976], [9.04059, 45.8464], [9.04546, 45.84968], [9.06642, 45.8761], [9.09065, 45.89906], [8.99257, 45.9698], [9.01618, 46.04928], [9.24503, 46.23616], [9.29226, 46.32717], [9.25502, 46.43743], [9.28136, 46.49685], [9.36128, 46.5081], [9.40487, 46.46621], [9.45936, 46.50873], [9.46117, 46.37481], [9.57015, 46.2958], [9.71273, 46.29266], [9.73086, 46.35071], [9.95249, 46.38045], [10.07055, 46.21668], [10.14439, 46.22992], [10.17862, 46.25626], [10.10506, 46.3372], [10.165, 46.41051], [10.03715, 46.44479], [10.10307, 46.61003], [10.23674, 46.63484], [10.25309, 46.57432], [10.46136, 46.53164], [10.49375, 46.62049], [10.44686, 46.64162], [10.40475, 46.63671], [10.38659, 46.67847], [10.47197, 46.85698], [10.48376, 46.93891], [10.36933, 47.00212], [10.30031, 46.92093], [10.24128, 46.93147], [10.22675, 46.86942], [10.10715, 46.84296], [9.98058, 46.91434], [9.88266, 46.93343], [9.87935, 47.01337], [9.60717, 47.06091], [9.55721, 47.04762], [9.54041, 47.06495], [9.47548, 47.05257], [9.47139, 47.06402], [9.51362, 47.08505], [9.52089, 47.10019], [9.51044, 47.13727], [9.48774, 47.17402], [9.4891, 47.19346], [9.50318, 47.22153], [9.52406, 47.24959], [9.53116, 47.27029], [9.54773, 47.2809], [9.55857, 47.29919], [9.58513, 47.31334], [9.59978, 47.34671], [9.62476, 47.36639], [9.65427, 47.36824], [9.66243, 47.37136], [9.6711, 47.37824], [9.67445, 47.38429], [9.67334, 47.39191], [9.6629, 47.39591], [9.65136, 47.40504], [9.65043, 47.41937], [9.6446, 47.43233], [9.64483, 47.43842], [9.65863, 47.44847], [9.65728, 47.45383], [9.6423, 47.45599], [9.62475, 47.45685], [9.62158, 47.45858], [9.60841, 47.47178], [9.60484, 47.46358], [9.60205, 47.46165], [9.59482, 47.46305], [9.58208, 47.48344], [9.56312, 47.49495], [9.55125, 47.53629], [9.25619, 47.65939], [9.18203, 47.65598], [9.17593, 47.65399], [9.1755, 47.65584], [9.1705, 47.65513], [9.15181, 47.66904], [9.13845, 47.66389], [9.09891, 47.67801], [9.02093, 47.6868], [8.94093, 47.65596], [8.89946, 47.64769], [8.87625, 47.65441], [8.87383, 47.67045], [8.85065, 47.68209], [8.86989, 47.70504], [8.82002, 47.71458], [8.80663, 47.73821], [8.77309, 47.72059], [8.76965, 47.7075], [8.79966, 47.70222], [8.79511, 47.67462], [8.75856, 47.68969], [8.72809, 47.69282]], [[8.95861, 45.96485], [8.96668, 45.98436], [8.97741, 45.98317], [8.97604, 45.96151], [8.95861, 45.96485]], [[8.70847, 47.68904], [8.68985, 47.69552], [8.66837, 47.68437], [8.65769, 47.68928], [8.67508, 47.6979], [8.66416, 47.71367], [8.70237, 47.71453], [8.71773, 47.69088], [8.70847, 47.68904]]]]
24503 nameEn: "C\xF4te d'Ivoire",
24504 groups: ["011", "202", "002", "UN"],
24505 callingCodes: ["225"]
24508 type: "MultiPolygon",
24509 coordinates: [[[[-7.52774, 3.7105], [-3.34019, 4.17519], [-3.10675, 5.08515], [-3.11073, 5.12675], [-3.063, 5.13665], [-2.96554, 5.10397], [-2.95261, 5.12477], [-2.75502, 5.10657], [-2.73074, 5.1364], [-2.77625, 5.34621], [-2.72737, 5.34789], [-2.76614, 5.60963], [-2.85378, 5.65156], [-2.93132, 5.62137], [-2.96671, 5.6415], [-2.95323, 5.71865], [-3.01896, 5.71697], [-3.25999, 6.62521], [-3.21954, 6.74407], [-3.23327, 6.81744], [-2.95438, 7.23737], [-2.97822, 7.27165], [-2.92339, 7.60847], [-2.79467, 7.86002], [-2.78395, 7.94974], [-2.74819, 7.92613], [-2.67787, 8.02055], [-2.61232, 8.02645], [-2.62901, 8.11495], [-2.49037, 8.20872], [-2.58243, 8.7789], [-2.66357, 9.01771], [-2.77799, 9.04949], [-2.69814, 9.22717], [-2.68802, 9.49343], [-2.76494, 9.40778], [-2.93012, 9.57403], [-3.00765, 9.74019], [-3.16609, 9.85147], [-3.19306, 9.93781], [-3.27228, 9.84981], [-3.31779, 9.91125], [-3.69703, 9.94279], [-4.25999, 9.76012], [-4.31392, 9.60062], [-4.6426, 9.70696], [-4.96621, 9.89132], [-4.96453, 9.99923], [-5.12465, 10.29788], [-5.39602, 10.2929], [-5.51058, 10.43177], [-5.65135, 10.46767], [-5.78124, 10.43952], [-5.99478, 10.19694], [-6.18851, 10.24244], [-6.1731, 10.46983], [-6.24795, 10.74248], [-6.325, 10.68624], [-6.40646, 10.69922], [-6.42847, 10.5694], [-6.52974, 10.59104], [-6.63541, 10.66893], [-6.68164, 10.35074], [-6.93921, 10.35291], [-7.01186, 10.25111], [-6.97444, 10.21644], [-7.00966, 10.15794], [-7.0603, 10.14711], [-7.13331, 10.24877], [-7.3707, 10.24677], [-7.44555, 10.44602], [-7.52261, 10.4655], [-7.54462, 10.40921], [-7.63048, 10.46334], [-7.92107, 10.15577], [-7.97971, 10.17117], [-8.01225, 10.1021], [-8.11921, 10.04577], [-8.15652, 9.94288], [-8.09434, 9.86936], [-8.14657, 9.55062], [-8.03463, 9.39604], [-7.85056, 9.41812], [-7.90777, 9.20456], [-7.73862, 9.08422], [-7.92518, 8.99332], [-7.95503, 8.81146], [-7.69882, 8.66148], [-7.65653, 8.36873], [-7.92518, 8.50652], [-8.22991, 8.48438], [-8.2411, 8.24196], [-8.062, 8.16071], [-7.98675, 8.20134], [-7.99919, 8.11023], [-7.94695, 8.00925], [-8.06449, 8.04989], [-8.13414, 7.87991], [-8.09931, 7.78626], [-8.21374, 7.54466], [-8.4003, 7.6285], [-8.47114, 7.55676], [-8.41935, 7.51203], [-8.37458, 7.25794], [-8.29249, 7.1691], [-8.31736, 6.82837], [-8.59456, 6.50612], [-8.48652, 6.43797], [-8.45666, 6.49977], [-8.38453, 6.35887], [-8.3298, 6.36381], [-8.17557, 6.28222], [-8.00642, 6.31684], [-7.90692, 6.27728], [-7.83478, 6.20309], [-7.8497, 6.08932], [-7.79747, 6.07696], [-7.78254, 5.99037], [-7.70294, 5.90625], [-7.67309, 5.94337], [-7.48155, 5.80974], [-7.46165, 5.84934], [-7.43677, 5.84687], [-7.43926, 5.74787], [-7.37209, 5.61173], [-7.43428, 5.42355], [-7.36463, 5.32944], [-7.46165, 5.26256], [-7.48901, 5.14118], [-7.55369, 5.08667], [-7.53876, 4.94294], [-7.59349, 4.8909], [-7.53259, 4.35145], [-7.52774, 3.7105]]]]
24517 wikidata: "Q26988",
24518 nameEn: "Cook Islands",
24520 groups: ["061", "009", "UN"],
24522 callingCodes: ["682"]
24525 type: "MultiPolygon",
24526 coordinates: [[[[-168.15106, -10.26955], [-156.45576, -31.75456], [-156.48634, -15.52824], [-156.50903, -7.4975], [-168.15106, -10.26955]]]]
24536 groups: ["005", "419", "019", "UN"],
24537 callingCodes: ["56"]
24540 type: "MultiPolygon",
24541 coordinates: [[[[-68.60702, -52.65781], [-68.41683, -52.33516], [-69.97824, -52.00845], [-71.99889, -51.98018], [-72.33873, -51.59954], [-72.31343, -50.58411], [-73.15765, -50.78337], [-73.55259, -49.92488], [-73.45156, -49.79461], [-73.09655, -49.14342], [-72.56894, -48.81116], [-72.54042, -48.52392], [-72.27662, -48.28727], [-72.50478, -47.80586], [-71.94152, -47.13595], [-71.68577, -46.55385], [-71.75614, -45.61611], [-71.35687, -45.22075], [-72.06985, -44.81756], [-71.26418, -44.75684], [-71.16436, -44.46244], [-71.81318, -44.38097], [-71.64206, -43.64774], [-72.14828, -42.85321], [-72.15541, -42.15941], [-71.74901, -42.11711], [-71.92726, -40.72714], [-71.37826, -38.91474], [-70.89532, -38.6923], [-71.24279, -37.20264], [-70.95047, -36.4321], [-70.38008, -36.02375], [-70.49416, -35.24145], [-69.87386, -34.13344], [-69.88099, -33.34489], [-70.55832, -31.51559], [-70.14479, -30.36595], [-69.8596, -30.26131], [-69.99507, -29.28351], [-69.80969, -29.07185], [-69.66709, -28.44055], [-69.22504, -27.95042], [-68.77586, -27.16029], [-68.43363, -27.08414], [-68.27677, -26.90626], [-68.59048, -26.49861], [-68.56909, -26.28146], [-68.38372, -26.15353], [-68.57622, -25.32505], [-68.38372, -25.08636], [-68.56909, -24.69831], [-68.24825, -24.42596], [-67.33563, -24.04237], [-66.99632, -22.99839], [-67.18382, -22.81525], [-67.54284, -22.89771], [-67.85114, -22.87076], [-68.18816, -21.28614], [-68.40403, -20.94562], [-68.53957, -20.91542], [-68.55383, -20.7355], [-68.44023, -20.62701], [-68.7276, -20.46178], [-68.74273, -20.08817], [-68.57132, -20.03134], [-68.54611, -19.84651], [-68.66761, -19.72118], [-68.41218, -19.40499], [-68.61989, -19.27584], [-68.80602, -19.08355], [-68.87082, -19.06003], [-68.94987, -18.93302], [-69.07432, -18.28259], [-69.14807, -18.16893], [-69.07496, -18.03715], [-69.28671, -17.94844], [-69.34126, -17.72753], [-69.46623, -17.60518], [-69.46897, -17.4988], [-69.66483, -17.65083], [-69.79087, -17.65563], [-69.82868, -17.72048], [-69.75305, -17.94605], [-69.81607, -18.12582], [-69.96732, -18.25992], [-70.16394, -18.31737], [-70.31267, -18.31258], [-70.378, -18.3495], [-70.59118, -18.35072], [-113.52687, -26.52828], [-68.11646, -58.14883], [-66.07313, -55.19618], [-67.11046, -54.94199], [-67.46182, -54.92205], [-68.01394, -54.8753], [-68.60733, -54.9125], [-68.60702, -52.65781]]]]
24550 nameEn: "Cameroon",
24551 groups: ["017", "202", "002", "UN"],
24552 callingCodes: ["237"]
24555 type: "MultiPolygon",
24556 coordinates: [[[[14.83314, 12.62963], [14.55058, 12.78256], [14.56101, 12.91036], [14.46881, 13.08259], [14.08251, 13.0797], [14.20204, 12.53405], [14.17523, 12.41916], [14.22215, 12.36533], [14.4843, 12.35223], [14.6474, 12.17466], [14.61612, 11.7798], [14.55207, 11.72001], [14.64591, 11.66166], [14.6124, 11.51283], [14.17821, 11.23831], [13.97489, 11.30258], [13.78945, 11.00154], [13.7403, 11.00593], [13.70753, 10.94451], [13.73434, 10.9255], [13.54964, 10.61236], [13.5705, 10.53183], [13.43644, 10.13326], [13.34111, 10.12299], [13.25025, 10.03647], [13.25323, 10.00127], [13.286, 9.9822], [13.27409, 9.93232], [13.24132, 9.91031], [13.25025, 9.86042], [13.29941, 9.8296], [13.25472, 9.76795], [13.22642, 9.57266], [13.02385, 9.49334], [12.85628, 9.36698], [12.91958, 9.33905], [12.90022, 9.11411], [12.81085, 8.91992], [12.79, 8.75361], [12.71701, 8.7595], [12.68722, 8.65938], [12.44146, 8.6152], [12.4489, 8.52536], [12.26123, 8.43696], [12.24782, 8.17904], [12.19271, 8.10826], [12.20909, 7.97553], [11.99908, 7.67302], [12.01844, 7.52981], [11.93205, 7.47812], [11.84864, 7.26098], [11.87396, 7.09398], [11.63117, 6.9905], [11.55818, 6.86186], [11.57755, 6.74059], [11.51499, 6.60892], [11.42264, 6.5882], [11.42041, 6.53789], [11.09495, 6.51717], [11.09644, 6.68437], [10.94302, 6.69325], [10.8179, 6.83377], [10.83727, 6.9358], [10.60789, 7.06885], [10.59746, 7.14719], [10.57214, 7.16345], [10.53639, 6.93432], [10.21466, 6.88996], [10.15135, 7.03781], [9.86314, 6.77756], [9.77824, 6.79088], [9.70674, 6.51717], [9.51757, 6.43874], [8.84209, 5.82562], [8.88156, 5.78857], [8.83687, 5.68483], [8.92029, 5.58403], [8.78027, 5.1243], [8.60302, 4.87353], [8.34397, 4.30689], [9.22018, 3.72052], [9.81162, 2.33797], [9.82123, 2.35097], [9.83754, 2.32428], [9.83238, 2.29079], [9.84716, 2.24676], [9.89012, 2.20457], [9.90749, 2.20049], [9.991, 2.16561], [11.3561, 2.17217], [11.37116, 2.29975], [13.28534, 2.25716], [13.29457, 2.16106], [14.61145, 2.17866], [15.00996, 1.98887], [15.22634, 2.03243], [15.34776, 1.91264], [15.48942, 1.98265], [16.02959, 1.76483], [16.02647, 1.65591], [16.14634, 1.70259], [16.05294, 1.9811], [16.08563, 2.19733], [16.15568, 2.18955], [16.19357, 2.21537], [16.08252, 2.45708], [16.05449, 3.02306], [15.77725, 3.26835], [15.73522, 3.24348], [15.07686, 4.01805], [15.17482, 4.05131], [15.10644, 4.1362], [15.08609, 4.30282], [15.00825, 4.41458], [14.73383, 4.6135], [14.65489, 5.21343], [14.57083, 5.23979], [14.52724, 5.28319], [14.62531, 5.51411], [14.58951, 5.59777], [14.62375, 5.70466], [14.60974, 5.91838], [14.49455, 5.91683], [14.42917, 6.00508], [14.43073, 6.08867], [14.56149, 6.18928], [14.74206, 6.26356], [14.80122, 6.34866], [14.79966, 6.39043], [14.96311, 6.75693], [15.04717, 6.77085], [15.23397, 7.25135], [15.49743, 7.52179], [15.56964, 7.58936], [15.59272, 7.7696], [15.50743, 7.79302], [15.20426, 8.50892], [15.09484, 8.65982], [14.83566, 8.80557], [14.35707, 9.19611], [14.37094, 9.2954], [13.97544, 9.6365], [14.01793, 9.73169], [14.1317, 9.82413], [14.20411, 10.00055], [14.4673, 10.00264], [14.80082, 9.93818], [14.95722, 9.97926], [15.05999, 9.94845], [15.14043, 9.99246], [15.24618, 9.99246], [15.41408, 9.92876], [15.68761, 9.99344], [15.50535, 10.1098], [15.30874, 10.31063], [15.23724, 10.47764], [15.14936, 10.53915], [15.15532, 10.62846], [15.06737, 10.80921], [15.09127, 10.87431], [15.04957, 11.02347], [15.10021, 11.04101], [15.0585, 11.40481], [15.13149, 11.5537], [15.06595, 11.71126], [15.11579, 11.79313], [15.04808, 11.8731], [15.05786, 12.0608], [15.0349, 12.10698], [15.00146, 12.1223], [14.96952, 12.0925], [14.89019, 12.16593], [14.90827, 12.3269], [14.83314, 12.62963]]]]
24565 nameEn: "People's Republic of China"
24575 nameEn: "Colombia",
24576 groups: ["005", "419", "019", "UN"],
24577 callingCodes: ["57"]
24580 type: "MultiPolygon",
24581 coordinates: [[[[-71.19849, 12.65801], [-81.58685, 18.0025], [-82.06974, 14.49418], [-82.56142, 11.91792], [-78.79327, 9.93766], [-77.58292, 9.22278], [-77.32389, 8.81247], [-77.45064, 8.49991], [-77.17257, 7.97422], [-77.57185, 7.51147], [-77.72514, 7.72348], [-77.72157, 7.47612], [-77.81426, 7.48319], [-77.89178, 7.22681], [-78.06168, 7.07793], [-82.12561, 4.00341], [-78.87137, 1.47457], [-78.42749, 1.15389], [-77.85677, 0.80197], [-77.7148, 0.85003], [-77.68613, 0.83029], [-77.66416, 0.81604], [-77.67815, 0.73863], [-77.49984, 0.64476], [-77.52001, 0.40782], [-76.89177, 0.24736], [-76.4094, 0.24015], [-76.41215, 0.38228], [-76.23441, 0.42294], [-75.82927, 0.09578], [-75.25764, -0.11943], [-75.18513, -0.0308], [-74.42701, -0.50218], [-74.26675, -0.97229], [-73.65312, -1.26222], [-72.92587, -2.44514], [-71.75223, -2.15058], [-70.94377, -2.23142], [-70.04609, -2.73906], [-70.71396, -3.7921], [-70.52393, -3.87553], [-70.3374, -3.79505], [-69.94708, -4.2431], [-69.43395, -1.42219], [-69.4215, -1.01853], [-69.59796, -0.75136], [-69.603, -0.51947], [-70.03658, -0.19681], [-70.04162, 0.55437], [-69.47696, 0.71065], [-69.20976, 0.57958], [-69.14422, 0.84172], [-69.26017, 1.06856], [-69.82987, 1.07864], [-69.83491, 1.69353], [-69.53746, 1.76408], [-69.38621, 1.70865], [-68.18128, 1.72881], [-68.26699, 1.83463], [-68.18632, 2.00091], [-67.9292, 1.82455], [-67.40488, 2.22258], [-67.299, 1.87494], [-67.15784, 1.80439], [-67.08222, 1.17441], [-66.85795, 1.22998], [-67.21967, 2.35778], [-67.65696, 2.81691], [-67.85862, 2.79173], [-67.85862, 2.86727], [-67.30945, 3.38393], [-67.50067, 3.75812], [-67.62671, 3.74303], [-67.85358, 4.53249], [-67.83341, 5.31104], [-67.59141, 5.5369], [-67.63914, 5.64963], [-67.58558, 5.84537], [-67.43513, 5.98835], [-67.4625, 6.20625], [-67.60654, 6.2891], [-69.41843, 6.1072], [-70.10716, 6.96516], [-70.7596, 7.09799], [-71.03941, 6.98163], [-71.37234, 7.01588], [-71.42212, 7.03854], [-71.44118, 7.02116], [-71.82441, 7.04314], [-72.04895, 7.03837], [-72.19437, 7.37034], [-72.43132, 7.40034], [-72.47415, 7.48928], [-72.45321, 7.57232], [-72.47827, 7.65604], [-72.46763, 7.79518], [-72.44454, 7.86031], [-72.46183, 7.90682], [-72.45806, 7.91141], [-72.47042, 7.92306], [-72.48183, 7.92909], [-72.48801, 7.94329], [-72.47213, 7.96106], [-72.39137, 8.03534], [-72.35163, 8.01163], [-72.36987, 8.19976], [-72.4042, 8.36513], [-72.65474, 8.61428], [-72.77415, 9.10165], [-72.94052, 9.10663], [-73.02119, 9.27584], [-73.36905, 9.16636], [-72.98085, 9.85253], [-72.88002, 10.44309], [-72.4767, 11.1117], [-72.24983, 11.14138], [-71.9675, 11.65536], [-71.3275, 11.85], [-70.92579, 11.96275], [-71.19849, 12.65801]]]]
24588 wikidata: "Q161258",
24589 nameEn: "Clipperton Island",
24591 groups: ["013", "003", "019", "UN"],
24592 isoStatus: "excRes"
24595 type: "MultiPolygon",
24596 coordinates: [[[[-110.36279, 9.79626], [-108.755, 9.84085], [-109.04145, 11.13245], [-110.36279, 9.79626]]]]
24605 nameEn: "Costa Rica",
24606 groups: ["013", "003", "419", "019", "UN"],
24607 callingCodes: ["506"]
24610 type: "MultiPolygon",
24611 coordinates: [[[[-83.68276, 11.01562], [-83.66597, 10.79916], [-83.90838, 10.71161], [-84.68197, 11.07568], [-84.92439, 10.9497], [-85.60529, 11.22607], [-85.71223, 11.06868], [-86.14524, 11.09059], [-87.41779, 5.02401], [-82.94503, 7.93865], [-82.89978, 8.04083], [-82.89137, 8.05755], [-82.88641, 8.10219], [-82.9388, 8.26634], [-83.05209, 8.33394], [-82.93056, 8.43465], [-82.8679, 8.44042], [-82.8382, 8.48117], [-82.83322, 8.52464], [-82.83975, 8.54755], [-82.82739, 8.60153], [-82.8794, 8.6981], [-82.92068, 8.74832], [-82.91377, 8.774], [-82.88253, 8.83331], [-82.72126, 8.97125], [-82.93516, 9.07687], [-82.93516, 9.46741], [-82.84871, 9.4973], [-82.87919, 9.62645], [-82.77206, 9.59573], [-82.66667, 9.49746], [-82.61345, 9.49881], [-82.56507, 9.57279], [-82.51044, 9.65379], [-83.54024, 10.96805], [-83.68276, 11.01562]]]]
24621 groups: ["029", "003", "419", "019", "UN"],
24622 callingCodes: ["53"]
24625 type: "MultiPolygon",
24626 coordinates: [[[[-73.62304, 20.6935], [-82.02215, 24.23074], [-85.77883, 21.92705], [-74.81171, 18.82201], [-73.62304, 20.6935]]]]
24635 nameEn: "Cape Verde",
24636 groups: ["Q105472", "011", "202", "002", "UN"],
24637 callingCodes: ["238"]
24640 type: "MultiPolygon",
24641 coordinates: [[[[-28.81604, 14.57305], [-20.39702, 14.12816], [-23.37101, 19.134], [-28.81604, 14.57305]]]]
24649 wikidata: "Q25279",
24650 nameEn: "Cura\xE7ao",
24651 aliases: ["NL-CW"],
24653 groups: ["Q1451600", "029", "003", "419", "019", "UN"],
24654 callingCodes: ["599"]
24657 type: "MultiPolygon",
24658 coordinates: [[[[-68.90012, 12.62309], [-69.59009, 12.46019], [-68.99639, 11.79035], [-68.33524, 11.78151], [-68.90012, 12.62309]]]]
24666 wikidata: "Q31063",
24667 nameEn: "Christmas Island",
24669 groups: ["053", "009", "UN"],
24671 callingCodes: ["61"]
24674 type: "MultiPolygon",
24675 coordinates: [[[[105.66835, -9.31927], [104.67494, -11.2566], [106.66176, -11.14349], [105.66835, -9.31927]]]]
24684 nameEn: "Republic of Cyprus",
24685 groups: ["Q644636", "EU", "145", "142", "UN"],
24687 callingCodes: ["357"]
24690 type: "MultiPolygon",
24691 coordinates: [[[[32.46489, 35.48584], [30.15137, 34.08517], [32.74412, 34.43926], [32.75515, 34.64985], [32.76136, 34.68318], [32.79433, 34.67883], [32.82717, 34.70622], [32.86014, 34.70585], [32.86167, 34.68734], [32.9068, 34.66102], [32.91398, 34.67343], [32.93043, 34.67091], [32.92807, 34.66736], [32.93449, 34.66241], [32.93693, 34.67027], [32.94379, 34.67111], [32.94683, 34.67907], [32.95539, 34.68471], [32.99135, 34.68061], [32.98668, 34.67268], [32.99014, 34.65518], [32.97736, 34.65277], [32.97079, 34.66112], [32.95325, 34.66462], [32.94796, 34.6587], [32.94976, 34.65204], [32.95471, 34.64528], [32.95323, 34.64075], [32.95891, 34.62919], [32.96718, 34.63446], [32.96968, 34.64046], [33.0138, 34.64424], [33.26744, 34.49942], [33.83531, 34.73974], [33.70575, 34.97947], [33.70639, 34.99303], [33.71514, 35.00294], [33.69731, 35.01754], [33.69938, 35.03123], [33.67678, 35.03866], [33.63765, 35.03869], [33.61215, 35.0527], [33.59658, 35.03635], [33.567, 35.04803], [33.57478, 35.06049], [33.53975, 35.08151], [33.48915, 35.06594], [33.47666, 35.00701], [33.45256, 35.00288], [33.45178, 35.02078], [33.47825, 35.04103], [33.48136, 35.0636], [33.46813, 35.10564], [33.41675, 35.16325], [33.4076, 35.20062], [33.38575, 35.2018], [33.37248, 35.18698], [33.3717, 35.1788], [33.36569, 35.17479], [33.35612, 35.17402], [33.35596, 35.17942], [33.34964, 35.17803], [33.35056, 35.18328], [33.31955, 35.18096], [33.3072, 35.16816], [33.27068, 35.16815], [33.15138, 35.19504], [33.11105, 35.15639], [33.08249, 35.17319], [33.01192, 35.15639], [32.94471, 35.09422], [32.86406, 35.1043], [32.85733, 35.07742], [32.70779, 35.14127], [32.70947, 35.18328], [32.64864, 35.19967], [32.60361, 35.16647], [32.46489, 35.48584]]], [[[33.74144, 35.01053], [33.7492, 35.01319], [33.74983, 35.02274], [33.74265, 35.02329], [33.73781, 35.02181], [33.7343, 35.01178], [33.74144, 35.01053]]], [[[33.77312, 34.9976], [33.75994, 35.00113], [33.75682, 34.99916], [33.76605, 34.99543], [33.76738, 34.99188], [33.7778, 34.98981], [33.77843, 34.988], [33.78149, 34.98854], [33.78318, 34.98699], [33.78571, 34.98951], [33.78917, 34.98854], [33.79191, 34.98914], [33.78516, 34.99582], [33.77553, 34.99518], [33.77312, 34.9976]]]]
24701 groups: ["EU", "151", "150", "UN"],
24702 callingCodes: ["420"]
24705 type: "MultiPolygon",
24706 coordinates: [[[[14.82803, 50.86966], [14.79139, 50.81438], [14.70661, 50.84096], [14.61993, 50.86049], [14.63434, 50.8883], [14.65259, 50.90513], [14.64802, 50.93241], [14.58024, 50.91443], [14.56374, 50.922], [14.59702, 50.96148], [14.59908, 50.98685], [14.58215, 50.99306], [14.56432, 51.01008], [14.53438, 51.00374], [14.53321, 51.01679], [14.49873, 51.02242], [14.50809, 51.0427], [14.49991, 51.04692], [14.49154, 51.04382], [14.49202, 51.02286], [14.45827, 51.03712], [14.41335, 51.02086], [14.30098, 51.05515], [14.25665, 50.98935], [14.28776, 50.97718], [14.32353, 50.98556], [14.32793, 50.97379], [14.30251, 50.96606], [14.31422, 50.95243], [14.39848, 50.93866], [14.38691, 50.89907], [14.30098, 50.88448], [14.27123, 50.89386], [14.24314, 50.88761], [14.22331, 50.86049], [14.02982, 50.80662], [13.98864, 50.8177], [13.89113, 50.78533], [13.89444, 50.74142], [13.82942, 50.7251], [13.76316, 50.73487], [13.70204, 50.71771], [13.65977, 50.73096], [13.52474, 50.70394], [13.53748, 50.67654], [13.5226, 50.64721], [13.49742, 50.63133], [13.46413, 50.60102], [13.42189, 50.61243], [13.37485, 50.64931], [13.37805, 50.627], [13.32264, 50.60317], [13.32594, 50.58009], [13.29454, 50.57904], [13.25158, 50.59268], [13.19043, 50.50237], [13.13424, 50.51709], [13.08301, 50.50132], [13.0312, 50.50944], [13.02038, 50.4734], [13.02147, 50.44763], [12.98433, 50.42016], [12.94058, 50.40944], [12.82465, 50.45738], [12.73476, 50.43237], [12.73044, 50.42268], [12.70731, 50.39948], [12.67261, 50.41949], [12.51356, 50.39694], [12.48747, 50.37278], [12.49214, 50.35228], [12.48256, 50.34784], [12.46643, 50.35527], [12.43722, 50.33774], [12.43371, 50.32506], [12.39924, 50.32302], [12.40158, 50.29521], [12.36594, 50.28289], [12.35425, 50.23993], [12.33263, 50.24367], [12.32445, 50.20442], [12.33847, 50.19432], [12.32596, 50.17146], [12.29232, 50.17524], [12.28063, 50.19544], [12.28755, 50.22429], [12.23943, 50.24594], [12.24791, 50.25525], [12.26953, 50.25189], [12.25119, 50.27079], [12.20823, 50.2729], [12.18013, 50.32146], [12.10907, 50.32041], [12.13716, 50.27396], [12.09287, 50.25032], [12.19335, 50.19997], [12.21484, 50.16399], [12.1917, 50.13434], [12.2073, 50.10315], [12.23709, 50.10213], [12.27433, 50.0771], [12.26111, 50.06331], [12.30798, 50.05719], [12.49908, 49.97305], [12.47264, 49.94222], [12.55197, 49.92094], [12.48256, 49.83575], [12.46603, 49.78882], [12.40489, 49.76321], [12.4462, 49.70233], [12.52553, 49.68415], [12.53544, 49.61888], [12.56188, 49.6146], [12.60155, 49.52887], [12.64782, 49.52565], [12.64121, 49.47628], [12.669, 49.42935], [12.71227, 49.42363], [12.75854, 49.3989], [12.78168, 49.34618], [12.88414, 49.33541], [12.88249, 49.35479], [12.94859, 49.34079], [13.03618, 49.30417], [13.02957, 49.27399], [13.05883, 49.26259], [13.17665, 49.16713], [13.17019, 49.14339], [13.20405, 49.12303], [13.23689, 49.11412], [13.28242, 49.1228], [13.39479, 49.04812], [13.40802, 48.98851], [13.50221, 48.93752], [13.50552, 48.97441], [13.58319, 48.96899], [13.61624, 48.9462], [13.67739, 48.87886], [13.73854, 48.88538], [13.76994, 48.83537], [13.78977, 48.83319], [13.8096, 48.77877], [13.84023, 48.76988], [14.06151, 48.66873], [14.01482, 48.63788], [14.09104, 48.5943], [14.20691, 48.5898], [14.33909, 48.55852], [14.43076, 48.58855], [14.4587, 48.64695], [14.56139, 48.60429], [14.60808, 48.62881], [14.66762, 48.58215], [14.71794, 48.59794], [14.72756, 48.69502], [14.80584, 48.73489], [14.80821, 48.77711], [14.81545, 48.7874], [14.94773, 48.76268], [14.95641, 48.75915], [14.9758, 48.76857], [14.98112, 48.77524], [14.9782, 48.7766], [14.98032, 48.77959], [14.95072, 48.79101], [14.98917, 48.90082], [14.97612, 48.96983], [14.99878, 49.01444], [15.15534, 48.99056], [15.16358, 48.94278], [15.26177, 48.95766], [15.28305, 48.98831], [15.34823, 48.98444], [15.48027, 48.94481], [15.51357, 48.91549], [15.61622, 48.89541], [15.6921, 48.85973], [15.75341, 48.8516], [15.78087, 48.87644], [15.84404, 48.86921], [16.06034, 48.75436], [16.37345, 48.729], [16.40915, 48.74576], [16.46134, 48.80865], [16.67008, 48.77699], [16.68518, 48.7281], [16.71883, 48.73806], [16.79779, 48.70998], [16.90354, 48.71541], [16.93955, 48.60371], [17.00215, 48.70887], [17.11202, 48.82925], [17.19355, 48.87602], [17.29054, 48.85546], [17.3853, 48.80936], [17.45671, 48.85004], [17.5295, 48.81117], [17.7094, 48.86721], [17.73126, 48.87885], [17.77944, 48.92318], [17.87831, 48.92679], [17.91814, 49.01784], [18.06885, 49.03157], [18.1104, 49.08624], [18.15022, 49.24518], [18.18456, 49.28909], [18.36446, 49.3267], [18.4139, 49.36517], [18.4084, 49.40003], [18.44686, 49.39467], [18.54848, 49.47059], [18.53063, 49.49022], [18.57183, 49.51162], [18.6144, 49.49824], [18.67757, 49.50895], [18.74761, 49.492], [18.84521, 49.51672], [18.84786, 49.5446], [18.80479, 49.6815], [18.72838, 49.68163], [18.69817, 49.70473], [18.62676, 49.71983], [18.62943, 49.74603], [18.62645, 49.75002], [18.61368, 49.75426], [18.61278, 49.7618], [18.57183, 49.83334], [18.60341, 49.86256], [18.57045, 49.87849], [18.57697, 49.91565], [18.54299, 49.92537], [18.54495, 49.9079], [18.53423, 49.89906], [18.41604, 49.93498], [18.33562, 49.94747], [18.33278, 49.92415], [18.31914, 49.91565], [18.27794, 49.93863], [18.27107, 49.96779], [18.21752, 49.97309], [18.20241, 49.99958], [18.10628, 50.00223], [18.07898, 50.04535], [18.03212, 50.06574], [18.00396, 50.04954], [18.04585, 50.03311], [18.04585, 50.01194], [18.00191, 50.01723], [17.86886, 49.97452], [17.77669, 50.02253], [17.7506, 50.07896], [17.6888, 50.12037], [17.66683, 50.10275], [17.59404, 50.16437], [17.70528, 50.18812], [17.76296, 50.23382], [17.72176, 50.25665], [17.74648, 50.29966], [17.69292, 50.32859], [17.67764, 50.28977], [17.58889, 50.27837], [17.3702, 50.28123], [17.34548, 50.2628], [17.34273, 50.32947], [17.27681, 50.32246], [17.19991, 50.3654], [17.19579, 50.38817], [17.14498, 50.38117], [17.1224, 50.39494], [16.89229, 50.45117], [16.85933, 50.41093], [16.90877, 50.38642], [16.94448, 50.31281], [16.99803, 50.30316], [17.02138, 50.27772], [16.99803, 50.25753], [17.02825, 50.23118], [17.00353, 50.21449], [16.98018, 50.24172], [16.8456, 50.20834], [16.7014, 50.09659], [16.63137, 50.1142], [16.55446, 50.16613], [16.56407, 50.21009], [16.42674, 50.32509], [16.39379, 50.3207], [16.3622, 50.34875], [16.36495, 50.37679], [16.30289, 50.38292], [16.28118, 50.36891], [16.22821, 50.41054], [16.21585, 50.40627], [16.19526, 50.43291], [16.31413, 50.50274], [16.34572, 50.49575], [16.44597, 50.58041], [16.33611, 50.66579], [16.23174, 50.67101], [16.20839, 50.63096], [16.10265, 50.66405], [16.02437, 50.60046], [15.98317, 50.61528], [16.0175, 50.63009], [15.97219, 50.69799], [15.87331, 50.67188], [15.81683, 50.75666], [15.73186, 50.73885], [15.43798, 50.80833], [15.3803, 50.77187], [15.36656, 50.83956], [15.2773, 50.8907], [15.27043, 50.97724], [15.2361, 50.99886], [15.1743, 50.9833], [15.16744, 51.01959], [15.11937, 50.99021], [15.10152, 51.01095], [15.06218, 51.02269], [15.03895, 51.0123], [15.02433, 51.0242], [14.96419, 50.99108], [15.01088, 50.97984], [14.99852, 50.86817], [14.82803, 50.86966]]]]
24716 groups: ["EU", "155", "150", "UN"],
24717 callingCodes: ["49"]
24720 type: "MultiPolygon",
24721 coordinates: [[[[8.70847, 47.68904], [8.71773, 47.69088], [8.70237, 47.71453], [8.66416, 47.71367], [8.67508, 47.6979], [8.65769, 47.68928], [8.66837, 47.68437], [8.68985, 47.69552], [8.70847, 47.68904]]], [[[8.72617, 47.69651], [8.72809, 47.69282], [8.75856, 47.68969], [8.79511, 47.67462], [8.79966, 47.70222], [8.76965, 47.7075], [8.77309, 47.72059], [8.80663, 47.73821], [8.82002, 47.71458], [8.86989, 47.70504], [8.85065, 47.68209], [8.87383, 47.67045], [8.87625, 47.65441], [8.89946, 47.64769], [8.94093, 47.65596], [9.02093, 47.6868], [9.09891, 47.67801], [9.13845, 47.66389], [9.15181, 47.66904], [9.1705, 47.65513], [9.1755, 47.65584], [9.17593, 47.65399], [9.18203, 47.65598], [9.25619, 47.65939], [9.55125, 47.53629], [9.72736, 47.53457], [9.76748, 47.5934], [9.80254, 47.59419], [9.82591, 47.58158], [9.8189, 47.54688], [9.87499, 47.52953], [9.87733, 47.54688], [9.92407, 47.53111], [9.96029, 47.53899], [10.00003, 47.48216], [10.03859, 47.48927], [10.07131, 47.45531], [10.09001, 47.46005], [10.1052, 47.4316], [10.06897, 47.40709], [10.09819, 47.35724], [10.11805, 47.37228], [10.16362, 47.36674], [10.17648, 47.38889], [10.2127, 47.38019], [10.22774, 47.38904], [10.23757, 47.37609], [10.19998, 47.32832], [10.2147, 47.31014], [10.17648, 47.29149], [10.17531, 47.27167], [10.23257, 47.27088], [10.33424, 47.30813], [10.39851, 47.37623], [10.4324, 47.38494], [10.4359, 47.41183], [10.47446, 47.43318], [10.46278, 47.47901], [10.44291, 47.48453], [10.4324, 47.50111], [10.44992, 47.5524], [10.43473, 47.58394], [10.47329, 47.58552], [10.48849, 47.54057], [10.56912, 47.53584], [10.60337, 47.56755], [10.63456, 47.5591], [10.68832, 47.55752], [10.6965, 47.54253], [10.7596, 47.53228], [10.77596, 47.51729], [10.88814, 47.53701], [10.91268, 47.51334], [10.86945, 47.5015], [10.87061, 47.4786], [10.90918, 47.48571], [10.93839, 47.48018], [10.92437, 47.46991], [10.98513, 47.42882], [10.97111, 47.41617], [10.97111, 47.39561], [11.11835, 47.39719], [11.12536, 47.41222], [11.20482, 47.43198], [11.25157, 47.43277], [11.22002, 47.3964], [11.27844, 47.39956], [11.29597, 47.42566], [11.33804, 47.44937], [11.4175, 47.44621], [11.38128, 47.47465], [11.4362, 47.51413], [11.52618, 47.50939], [11.58578, 47.52281], [11.58811, 47.55515], [11.60681, 47.57881], [11.63934, 47.59202], [11.84052, 47.58354], [11.85572, 47.60166], [12.0088, 47.62451], [12.02282, 47.61033], [12.05788, 47.61742], [12.13734, 47.60639], [12.17824, 47.61506], [12.18145, 47.61019], [12.17737, 47.60121], [12.18568, 47.6049], [12.20398, 47.60667], [12.20801, 47.61082], [12.19895, 47.64085], [12.18507, 47.65984], [12.18347, 47.66663], [12.16769, 47.68167], [12.16217, 47.70105], [12.18303, 47.70065], [12.22571, 47.71776], [12.2542, 47.7433], [12.26238, 47.73544], [12.24017, 47.69534], [12.26004, 47.67725], [12.27991, 47.68827], [12.336, 47.69534], [12.37222, 47.68433], [12.43883, 47.6977], [12.44117, 47.6741], [12.50076, 47.62293], [12.53816, 47.63553], [12.57438, 47.63238], [12.6071, 47.6741], [12.7357, 47.6787], [12.77777, 47.66689], [12.76492, 47.64485], [12.82101, 47.61493], [12.77427, 47.58025], [12.80699, 47.54477], [12.84672, 47.54556], [12.85256, 47.52741], [12.9624, 47.47452], [12.98344, 47.48716], [12.9998, 47.46267], [13.04537, 47.49426], [13.03252, 47.53373], [13.05355, 47.56291], [13.04537, 47.58183], [13.06641, 47.58577], [13.06407, 47.60075], [13.09562, 47.63304], [13.07692, 47.68814], [13.01382, 47.72116], [12.98578, 47.7078], [12.92969, 47.71094], [12.91333, 47.7178], [12.90274, 47.72513], [12.91711, 47.74026], [12.9353, 47.74788], [12.94371, 47.76281], [12.93202, 47.77302], [12.96311, 47.79957], [12.98543, 47.82896], [13.00588, 47.84374], [12.94163, 47.92927], [12.93886, 47.94046], [12.93642, 47.94436], [12.93419, 47.94063], [12.92668, 47.93879], [12.91985, 47.94069], [12.9211, 47.95135], [12.91683, 47.95647], [12.87476, 47.96195], [12.8549, 48.01122], [12.76141, 48.07373], [12.74973, 48.10885], [12.7617, 48.12796], [12.78595, 48.12445], [12.80676, 48.14979], [12.82673, 48.15245], [12.8362, 48.15876], [12.836, 48.1647], [12.84475, 48.16556], [12.87126, 48.20318], [12.95306, 48.20629], [13.02083, 48.25689], [13.0851, 48.27711], [13.126, 48.27867], [13.18093, 48.29577], [13.26039, 48.29422], [13.30897, 48.31575], [13.40709, 48.37292], [13.43929, 48.43386], [13.42527, 48.45711], [13.45727, 48.51092], [13.43695, 48.55776], [13.45214, 48.56472], [13.46967, 48.55157], [13.50663, 48.57506], [13.50131, 48.58091], [13.51291, 48.59023], [13.57535, 48.55912], [13.59705, 48.57013], [13.62508, 48.55501], [13.65186, 48.55092], [13.66113, 48.53558], [13.72802, 48.51208], [13.74816, 48.53058], [13.7513, 48.5624], [13.76921, 48.55324], [13.80519, 48.58026], [13.80038, 48.59487], [13.82609, 48.62345], [13.81901, 48.6761], [13.81283, 48.68426], [13.81791, 48.69832], [13.79337, 48.71375], [13.81863, 48.73257], [13.82266, 48.75544], [13.84023, 48.76988], [13.8096, 48.77877], [13.78977, 48.83319], [13.76994, 48.83537], [13.73854, 48.88538], [13.67739, 48.87886], [13.61624, 48.9462], [13.58319, 48.96899], [13.50552, 48.97441], [13.50221, 48.93752], [13.40802, 48.98851], [13.39479, 49.04812], [13.28242, 49.1228], [13.23689, 49.11412], [13.20405, 49.12303], [13.17019, 49.14339], [13.17665, 49.16713], [13.05883, 49.26259], [13.02957, 49.27399], [13.03618, 49.30417], [12.94859, 49.34079], [12.88249, 49.35479], [12.88414, 49.33541], [12.78168, 49.34618], [12.75854, 49.3989], [12.71227, 49.42363], [12.669, 49.42935], [12.64121, 49.47628], [12.64782, 49.52565], [12.60155, 49.52887], [12.56188, 49.6146], [12.53544, 49.61888], [12.52553, 49.68415], [12.4462, 49.70233], [12.40489, 49.76321], [12.46603, 49.78882], [12.48256, 49.83575], [12.55197, 49.92094], [12.47264, 49.94222], [12.49908, 49.97305], [12.30798, 50.05719], [12.26111, 50.06331], [12.27433, 50.0771], [12.23709, 50.10213], [12.2073, 50.10315], [12.1917, 50.13434], [12.21484, 50.16399], [12.19335, 50.19997], [12.09287, 50.25032], [12.13716, 50.27396], [12.10907, 50.32041], [12.18013, 50.32146], [12.20823, 50.2729], [12.25119, 50.27079], [12.26953, 50.25189], [12.24791, 50.25525], [12.23943, 50.24594], [12.28755, 50.22429], [12.28063, 50.19544], [12.29232, 50.17524], [12.32596, 50.17146], [12.33847, 50.19432], [12.32445, 50.20442], [12.33263, 50.24367], [12.35425, 50.23993], [12.36594, 50.28289], [12.40158, 50.29521], [12.39924, 50.32302], [12.43371, 50.32506], [12.43722, 50.33774], [12.46643, 50.35527], [12.48256, 50.34784], [12.49214, 50.35228], [12.48747, 50.37278], [12.51356, 50.39694], [12.67261, 50.41949], [12.70731, 50.39948], [12.73044, 50.42268], [12.73476, 50.43237], [12.82465, 50.45738], [12.94058, 50.40944], [12.98433, 50.42016], [13.02147, 50.44763], [13.02038, 50.4734], [13.0312, 50.50944], [13.08301, 50.50132], [13.13424, 50.51709], [13.19043, 50.50237], [13.25158, 50.59268], [13.29454, 50.57904], [13.32594, 50.58009], [13.32264, 50.60317], [13.37805, 50.627], [13.37485, 50.64931], [13.42189, 50.61243], [13.46413, 50.60102], [13.49742, 50.63133], [13.5226, 50.64721], [13.53748, 50.67654], [13.52474, 50.70394], [13.65977, 50.73096], [13.70204, 50.71771], [13.76316, 50.73487], [13.82942, 50.7251], [13.89444, 50.74142], [13.89113, 50.78533], [13.98864, 50.8177], [14.02982, 50.80662], [14.22331, 50.86049], [14.24314, 50.88761], [14.27123, 50.89386], [14.30098, 50.88448], [14.38691, 50.89907], [14.39848, 50.93866], [14.31422, 50.95243], [14.30251, 50.96606], [14.32793, 50.97379], [14.32353, 50.98556], [14.28776, 50.97718], [14.25665, 50.98935], [14.30098, 51.05515], [14.41335, 51.02086], [14.45827, 51.03712], [14.49202, 51.02286], [14.49154, 51.04382], [14.49991, 51.04692], [14.50809, 51.0427], [14.49873, 51.02242], [14.53321, 51.01679], [14.53438, 51.00374], [14.56432, 51.01008], [14.58215, 50.99306], [14.59908, 50.98685], [14.59702, 50.96148], [14.56374, 50.922], [14.58024, 50.91443], [14.64802, 50.93241], [14.65259, 50.90513], [14.63434, 50.8883], [14.61993, 50.86049], [14.70661, 50.84096], [14.79139, 50.81438], [14.82803, 50.86966], [14.81664, 50.88148], [14.89681, 50.9422], [14.89252, 50.94999], [14.92942, 50.99744], [14.95529, 51.04552], [14.97938, 51.07742], [14.98229, 51.11354], [14.99689, 51.12205], [14.99079, 51.14284], [14.99646, 51.14365], [15.00083, 51.14974], [14.99414, 51.15813], [14.99311, 51.16249], [15.0047, 51.16874], [15.01242, 51.21285], [15.04288, 51.28387], [14.98008, 51.33449], [14.96899, 51.38367], [14.9652, 51.44793], [14.94749, 51.47155], [14.73219, 51.52922], [14.72652, 51.53902], [14.73047, 51.54606], [14.71125, 51.56209], [14.7727, 51.61263], [14.75759, 51.62318], [14.75392, 51.67445], [14.69065, 51.70842], [14.66386, 51.73282], [14.64625, 51.79472], [14.60493, 51.80473], [14.59089, 51.83302], [14.6588, 51.88359], [14.6933, 51.9044], [14.70601, 51.92944], [14.7177, 51.94048], [14.72163, 51.95188], [14.71836, 51.95606], [14.7139, 51.95643], [14.70488, 51.97679], [14.71339, 52.00337], [14.76026, 52.06624], [14.72971, 52.09167], [14.6917, 52.10283], [14.67683, 52.13936], [14.70616, 52.16927], [14.68344, 52.19612], [14.71319, 52.22144], [14.70139, 52.25038], [14.58149, 52.28007], [14.56378, 52.33838], [14.55228, 52.35264], [14.54423, 52.42568], [14.63056, 52.48993], [14.60081, 52.53116], [14.6289, 52.57136], [14.61073, 52.59847], [14.22071, 52.81175], [14.13806, 52.82392], [14.12256, 52.84311], [14.15873, 52.87715], [14.14056, 52.95786], [14.25954, 53.00264], [14.35044, 53.05829], [14.38679, 53.13669], [14.36696, 53.16444], [14.37853, 53.20405], [14.40662, 53.21098], [14.45125, 53.26241], [14.44133, 53.27427], [14.4215, 53.27724], [14.35209, 53.49506], [14.3273, 53.50587], [14.30416, 53.55499], [14.31904, 53.61581], [14.2853, 53.63392], [14.28477, 53.65955], [14.27133, 53.66613], [14.2836, 53.67721], [14.26782, 53.69866], [14.27249, 53.74464], [14.21323, 53.8664], [14.20823, 53.90776], [14.18544, 53.91258], [14.20647, 53.91671], [14.22634, 53.9291], [14.20811, 54.12784], [13.93395, 54.84044], [12.85844, 54.82438], [11.90309, 54.38543], [11.00303, 54.63689], [10.31111, 54.65968], [10.16755, 54.73883], [9.89314, 54.84171], [9.73563, 54.8247], [9.61187, 54.85548], [9.62734, 54.88057], [9.58937, 54.88785], [9.4659, 54.83131], [9.43155, 54.82586], [9.41213, 54.84254], [9.38532, 54.83968], [9.36496, 54.81749], [9.33849, 54.80233], [9.32771, 54.80602], [9.2474, 54.8112], [9.23445, 54.83432], [9.24631, 54.84726], [9.20571, 54.85841], [9.14275, 54.87421], [9.04629, 54.87249], [8.92795, 54.90452], [8.81178, 54.90518], [8.76387, 54.8948], [8.63979, 54.91069], [8.55769, 54.91837], [8.45719, 55.06747], [8.02459, 55.09613], [5.45168, 54.20039], [6.91025, 53.44221], [7.00198, 53.32672], [7.19052, 53.31866], [7.21679, 53.20058], [7.22681, 53.18165], [7.17898, 53.13817], [7.21694, 53.00742], [7.07253, 52.81083], [7.04557, 52.63318], [6.77307, 52.65375], [6.71641, 52.62905], [6.69507, 52.488], [6.94293, 52.43597], [6.99041, 52.47235], [7.03417, 52.40237], [7.07044, 52.37805], [7.02703, 52.27941], [7.06365, 52.23789], [7.03729, 52.22695], [6.9897, 52.2271], [6.97189, 52.20329], [6.83984, 52.11728], [6.76117, 52.11895], [6.68128, 52.05052], [6.83035, 51.9905], [6.82357, 51.96711], [6.72319, 51.89518], [6.68386, 51.91861], [6.58556, 51.89386], [6.50231, 51.86313], [6.47179, 51.85395], [6.38815, 51.87257], [6.40704, 51.82771], [6.30593, 51.84998], [6.29872, 51.86801], [6.21443, 51.86801], [6.15349, 51.90439], [6.11551, 51.89769], [6.16902, 51.84094], [6.10337, 51.84829], [6.06705, 51.86136], [5.99848, 51.83195], [5.94568, 51.82786], [5.98665, 51.76944], [5.95003, 51.7493], [6.04091, 51.71821], [6.02767, 51.6742], [6.11759, 51.65609], [6.09055, 51.60564], [6.18017, 51.54096], [6.21724, 51.48568], [6.20654, 51.40049], [6.22641, 51.39948], [6.22674, 51.36135], [6.16977, 51.33169], [6.07889, 51.24432], [6.07889, 51.17038], [6.17384, 51.19589], [6.16706, 51.15677], [5.98292, 51.07469], [5.9541, 51.03496], [5.9134, 51.06736], [5.86735, 51.05182], [5.87849, 51.01969], [5.90493, 51.00198], [5.90296, 50.97356], [5.95282, 50.98728], [6.02697, 50.98303], [6.01615, 50.93367], [6.09297, 50.92066], [6.07486, 50.89307], [6.08805, 50.87223], [6.07693, 50.86025], [6.07431, 50.84674], [6.05702, 50.85179], [6.05623, 50.8572], [6.01921, 50.84435], [6.02328, 50.81694], [6.00462, 50.80065], [5.98404, 50.80988], [5.97497, 50.79992], [6.02624, 50.77453], [6.01976, 50.75398], [6.03889, 50.74618], [6.0326, 50.72647], [6.0406, 50.71848], [6.04428, 50.72861], [6.11707, 50.72231], [6.17852, 50.6245], [6.26957, 50.62444], [6.2476, 50.60392], [6.24888, 50.59869], [6.24005, 50.58732], [6.22581, 50.5907], [6.20281, 50.56952], [6.17739, 50.55875], [6.17802, 50.54179], [6.19735, 50.53576], [6.19579, 50.5313], [6.18716, 50.52653], [6.19193, 50.5212], [6.20599, 50.52089], [6.22335, 50.49578], [6.26637, 50.50272], [6.30809, 50.50058], [6.3465, 50.48833], [6.34005, 50.46083], [6.37219, 50.45397], [6.36852, 50.40776], [6.34406, 50.37994], [6.3688, 50.35898], [6.40785, 50.33557], [6.40641, 50.32425], [6.35701, 50.31139], [6.32488, 50.32333], [6.29949, 50.30887], [6.28797, 50.27458], [6.208, 50.25179], [6.16853, 50.2234], [6.18364, 50.20815], [6.18739, 50.1822], [6.14588, 50.17106], [6.14132, 50.14971], [6.15298, 50.14126], [6.1379, 50.12964], [6.12055, 50.09171], [6.11274, 50.05916], [6.13458, 50.04141], [6.13044, 50.02929], [6.14666, 50.02207], [6.13794, 50.01466], [6.13273, 50.02019], [6.1295, 50.01849], [6.13806, 50.01056], [6.14948, 50.00908], [6.14147, 49.99563], [6.1701, 49.98518], [6.16466, 49.97086], [6.17872, 49.9537], [6.18554, 49.95622], [6.18045, 49.96611], [6.19089, 49.96991], [6.19856, 49.95053], [6.22094, 49.94955], [6.22608, 49.929], [6.21882, 49.92403], [6.22926, 49.92096], [6.23496, 49.89972], [6.26146, 49.88203], [6.28874, 49.87592], [6.29692, 49.86685], [6.30963, 49.87021], [6.32303, 49.85133], [6.32098, 49.83728], [6.33585, 49.83785], [6.34267, 49.84974], [6.36576, 49.85032], [6.40022, 49.82029], [6.42521, 49.81591], [6.42905, 49.81091], [6.44131, 49.81443], [6.45425, 49.81164], [6.47111, 49.82263], [6.48718, 49.81267], [6.50647, 49.80916], [6.51215, 49.80124], [6.52121, 49.81338], [6.53122, 49.80666], [6.52169, 49.79787], [6.50534, 49.78952], [6.51669, 49.78336], [6.51056, 49.77515], [6.51828, 49.76855], [6.51646, 49.75961], [6.50174, 49.75292], [6.50193, 49.73291], [6.51805, 49.72425], [6.51397, 49.72058], [6.50261, 49.72718], [6.49535, 49.72645], [6.49694, 49.72205], [6.5042, 49.71808], [6.50647, 49.71353], [6.49785, 49.71118], [6.48014, 49.69767], [6.46048, 49.69092], [6.44654, 49.67799], [6.42937, 49.66857], [6.42726, 49.66078], [6.43768, 49.66021], [6.4413, 49.65722], [6.41861, 49.61723], [6.39822, 49.60081], [6.385, 49.59946], [6.37464, 49.58886], [6.38342, 49.5799], [6.38024, 49.57593], [6.36676, 49.57813], [6.35825, 49.57053], [6.38228, 49.55855], [6.38072, 49.55171], [6.35666, 49.52931], [6.36788, 49.50377], [6.36907, 49.48931], [6.36778, 49.46937], [6.38352, 49.46463], [6.39168, 49.4667], [6.40274, 49.46546], [6.42432, 49.47683], [6.55404, 49.42464], [6.533, 49.40748], [6.60091, 49.36864], [6.58807, 49.35358], [6.572, 49.35027], [6.60186, 49.31055], [6.66583, 49.28065], [6.69274, 49.21661], [6.71843, 49.2208], [6.73256, 49.20486], [6.71137, 49.18808], [6.73765, 49.16375], [6.78265, 49.16793], [6.83385, 49.15162], [6.84703, 49.15734], [6.86225, 49.18185], [6.85016, 49.19354], [6.85119, 49.20038], [6.83555, 49.21249], [6.85939, 49.22376], [6.89298, 49.20863], [6.91875, 49.22261], [6.93831, 49.2223], [6.94028, 49.21641], [6.95963, 49.203], [6.97273, 49.2099], [7.01318, 49.19018], [7.03459, 49.19096], [7.0274, 49.17042], [7.03178, 49.15734], [7.04662, 49.13724], [7.04409, 49.12123], [7.04843, 49.11422], [7.05548, 49.11185], [7.06642, 49.11415], [7.07162, 49.1255], [7.09007, 49.13094], [7.07859, 49.15031], [7.10715, 49.15631], [7.10384, 49.13787], [7.12504, 49.14253], [7.1358, 49.1282], [7.1593, 49.1204], [7.23473, 49.12971], [7.29514, 49.11426], [7.3195, 49.14231], [7.35995, 49.14399], [7.3662, 49.17308], [7.44052, 49.18354], [7.44455, 49.16765], [7.49473, 49.17], [7.49172, 49.13915], [7.53012, 49.09818], [7.56416, 49.08136], [7.62575, 49.07654], [7.63618, 49.05428], [7.75948, 49.04562], [7.79557, 49.06583], [7.86386, 49.03499], [7.93641, 49.05544], [7.97783, 49.03161], [8.14189, 48.97833], [8.22604, 48.97352], [8.20031, 48.95856], [8.19989, 48.95825], [8.12813, 48.87985], [8.10253, 48.81829], [8.06802, 48.78957], [8.0326, 48.79017], [8.01534, 48.76085], [7.96994, 48.75606], [7.96812, 48.72491], [7.89002, 48.66317], [7.84098, 48.64217], [7.80057, 48.5857], [7.80167, 48.54758], [7.80647, 48.51239], [7.76833, 48.48945], [7.73109, 48.39192], [7.74562, 48.32736], [7.69022, 48.30018], [7.6648, 48.22219], [7.57137, 48.12292], [7.56966, 48.03265], [7.62302, 47.97898], [7.55673, 47.87371], [7.52921, 47.77747], [7.54761, 47.72912], [7.53722, 47.71635], [7.51266, 47.70197], [7.51915, 47.68335], [7.52067, 47.66437], [7.53384, 47.65115], [7.5591, 47.63849], [7.57423, 47.61628], [7.58851, 47.60794], [7.59301, 47.60058], [7.58945, 47.59017], [7.60523, 47.58519], [7.60459, 47.57869], [7.61929, 47.57683], [7.64309, 47.59151], [7.64213, 47.5944], [7.64599, 47.59695], [7.67395, 47.59212], [7.68229, 47.59905], [7.69385, 47.60099], [7.68486, 47.59601], [7.67115, 47.5871], [7.68904, 47.57133], [7.67655, 47.56435], [7.63338, 47.56256], [7.65083, 47.54662], [7.66174, 47.54554], [7.6656, 47.53752], [7.68101, 47.53232], [7.69642, 47.53297], [7.71961, 47.54219], [7.75261, 47.54599], [7.79486, 47.55691], [7.81901, 47.58798], [7.84412, 47.5841], [7.88664, 47.58854], [7.90673, 47.57674], [7.91251, 47.55031], [7.94494, 47.54511], [7.95682, 47.55789], [7.97581, 47.55493], [8.00113, 47.55616], [8.02136, 47.55096], [8.04383, 47.55443], [8.06663, 47.56374], [8.08557, 47.55768], [8.10002, 47.56504], [8.10395, 47.57918], [8.11543, 47.5841], [8.13662, 47.58432], [8.13823, 47.59147], [8.14947, 47.59558], [8.1652, 47.5945], [8.19378, 47.61636], [8.20617, 47.62141], [8.22011, 47.6181], [8.22577, 47.60385], [8.23809, 47.61204], [8.25863, 47.61571], [8.26313, 47.6103], [8.2824, 47.61225], [8.29722, 47.60603], [8.29524, 47.5919], [8.30277, 47.58607], [8.32735, 47.57133], [8.35512, 47.57014], [8.38273, 47.56608], [8.39477, 47.57826], [8.43235, 47.56617], [8.49431, 47.58107], [8.48949, 47.588], [8.46637, 47.58389], [8.45578, 47.60121], [8.50747, 47.61897], [8.51686, 47.63476], [8.55756, 47.62394], [8.57586, 47.59537], [8.60348, 47.61204], [8.59545, 47.64298], [8.60701, 47.65271], [8.61471, 47.64514], [8.60412, 47.63735], [8.62049, 47.63757], [8.62884, 47.65098], [8.61113, 47.66332], [8.6052, 47.67258], [8.57683, 47.66158], [8.56141, 47.67088], [8.52801, 47.66059], [8.5322, 47.64687], [8.49656, 47.64709], [8.46605, 47.64103], [8.4667, 47.65747], [8.44711, 47.65379], [8.42264, 47.66667], [8.41346, 47.66676], [8.40473, 47.67499], [8.4211, 47.68407], [8.40569, 47.69855], [8.44807, 47.72426], [8.45771, 47.7493], [8.48868, 47.77215], [8.56814, 47.78001], [8.56415, 47.80633], [8.61657, 47.79998], [8.62408, 47.7626], [8.64425, 47.76398], [8.65292, 47.80066], [8.68022, 47.78599], [8.68985, 47.75686], [8.71778, 47.76571], [8.74251, 47.75168], [8.70543, 47.73121], [8.73671, 47.7169], [8.72617, 47.69651]]]]
24728 wikidata: "Q184851",
24729 nameEn: "Diego Garcia",
24731 groups: ["IO", "BOTS", "014", "202", "002", "UN"],
24732 isoStatus: "excRes",
24733 callingCodes: ["246"]
24736 type: "MultiPolygon",
24737 coordinates: [[[[73.14823, -7.76302], [73.09982, -6.07324], [71.43792, -7.73904], [73.14823, -7.76302]]]]
24746 nameEn: "Djibouti",
24747 groups: ["014", "202", "002", "UN"],
24748 callingCodes: ["253"]
24751 type: "MultiPolygon",
24752 coordinates: [[[[43.90659, 12.3823], [43.90659, 12.3823], [43.32909, 12.59711], [43.29075, 12.79154], [42.86195, 12.58747], [42.7996, 12.42629], [42.6957, 12.36201], [42.46941, 12.52661], [42.4037, 12.46478], [41.95461, 11.81157], [41.82878, 11.72361], [41.77727, 11.49902], [41.8096, 11.33606], [41.80056, 10.97127], [42.06302, 10.92599], [42.13691, 10.97586], [42.42669, 10.98493], [42.62989, 11.09711], [42.75111, 11.06992], [42.79037, 10.98493], [42.95776, 10.98533], [43.90659, 12.3823]]]]
24760 wikidata: "Q756617",
24761 nameEn: "Kingdom of Denmark"
24771 nameEn: "Dominica",
24772 groups: ["029", "003", "419", "019", "UN"],
24774 roadSpeedUnit: "mph",
24775 callingCodes: ["1 767"]
24778 type: "MultiPolygon",
24779 coordinates: [[[[-61.32485, 14.91445], [-60.86656, 15.82603], [-61.95646, 15.5094], [-61.32485, 14.91445]]]]
24788 nameEn: "Dominican Republic",
24789 groups: ["029", "003", "419", "019", "UN"],
24790 callingCodes: ["1 809", "1 829", "1 849"]
24793 type: "MultiPolygon",
24794 coordinates: [[[[-67.87844, 21.7938], [-72.38946, 20.27111], [-71.77419, 19.73128], [-71.75865, 19.70231], [-71.7429, 19.58445], [-71.71449, 19.55364], [-71.71268, 19.53374], [-71.6802, 19.45008], [-71.69448, 19.37866], [-71.77766, 19.33823], [-71.73229, 19.26686], [-71.62642, 19.21212], [-71.65337, 19.11759], [-71.69938, 19.10916], [-71.71088, 19.08353], [-71.74088, 19.0437], [-71.88102, 18.95007], [-71.77766, 18.95007], [-71.72624, 18.87802], [-71.71885, 18.78423], [-71.82556, 18.62551], [-71.95412, 18.64939], [-72.00201, 18.62312], [-71.88102, 18.50125], [-71.90875, 18.45821], [-71.69952, 18.34101], [-71.78271, 18.18302], [-71.75465, 18.14405], [-71.74994, 18.11115], [-71.73783, 18.07177], [-71.75671, 18.03456], [-72.29523, 17.48026], [-68.39466, 16.14167], [-67.87844, 21.7938]]]]
24804 groups: ["015", "002", "UN"],
24805 callingCodes: ["213"]
24808 type: "MultiPolygon",
24809 coordinates: [[[[8.59123, 37.14286], [5.10072, 39.89531], [-2.27707, 35.35051], [-2.21248, 35.08532], [-2.21445, 35.04378], [-2.04734, 34.93218], [-1.97833, 34.93218], [-1.97469, 34.886], [-1.73707, 34.74226], [-1.84569, 34.61907], [-1.69788, 34.48056], [-1.78042, 34.39018], [-1.64666, 34.10405], [-1.73494, 33.71721], [-1.59508, 33.59929], [-1.67067, 33.27084], [-1.46249, 33.0499], [-1.54244, 32.95499], [-1.37794, 32.73628], [-0.9912, 32.52467], [-1.24998, 32.32993], [-1.24453, 32.1917], [-1.15735, 32.12096], [-1.22829, 32.07832], [-2.46166, 32.16603], [-2.93873, 32.06557], [-2.82784, 31.79459], [-3.66314, 31.6339], [-3.66386, 31.39202], [-3.77647, 31.31912], [-3.77103, 31.14984], [-3.54944, 31.0503], [-3.65418, 30.85566], [-3.64735, 30.67539], [-4.31774, 30.53229], [-4.6058, 30.28343], [-5.21671, 29.95253], [-5.58831, 29.48103], [-5.72121, 29.52322], [-5.75616, 29.61407], [-6.69965, 29.51623], [-6.78351, 29.44634], [-6.95824, 29.50924], [-7.61585, 29.36252], [-8.6715, 28.71194], [-8.66879, 27.6666], [-8.66674, 27.31569], [-4.83423, 24.99935], [1.15698, 21.12843], [1.20992, 20.73533], [3.24648, 19.81703], [3.12501, 19.1366], [3.36082, 18.9745], [4.26651, 19.14224], [5.8153, 19.45101], [7.38361, 20.79165], [7.48273, 20.87258], [11.96886, 23.51735], [11.62498, 24.26669], [11.41061, 24.21456], [10.85323, 24.5595], [10.33159, 24.5465], [10.02432, 24.98124], [10.03146, 25.35635], [9.38834, 26.19288], [9.51696, 26.39148], [9.89569, 26.57696], [9.78136, 29.40961], [9.3876, 30.16738], [9.55544, 30.23971], [9.07483, 32.07865], [8.35999, 32.50101], [8.31895, 32.83483], [8.1179, 33.05086], [8.11433, 33.10175], [7.83028, 33.18851], [7.73687, 33.42114], [7.54088, 33.7726], [7.52851, 34.06493], [7.66174, 34.20167], [7.74207, 34.16492], [7.81242, 34.21841], [7.86264, 34.3987], [8.20482, 34.57575], [8.29655, 34.72798], [8.25189, 34.92009], [8.30727, 34.95378], [8.3555, 35.10007], [8.47318, 35.23376], [8.30329, 35.29884], [8.36086, 35.47774], [8.35371, 35.66373], [8.26472, 35.73669], [8.2626, 35.91733], [8.40731, 36.42208], [8.18936, 36.44939], [8.16167, 36.48817], [8.47609, 36.66607], [8.46537, 36.7706], [8.57613, 36.78062], [8.67706, 36.8364], [8.62972, 36.86499], [8.64044, 36.9401], [8.59123, 37.14286]]]]
24815 wikidata: "Q28868874",
24816 nameEn: "Ceuta, Melilla",
24818 level: "territory",
24819 isoStatus: "excRes"
24841 groups: ["EU", "154", "150", "UN"],
24842 callingCodes: ["372"]
24845 type: "MultiPolygon",
24846 coordinates: [[[[26.32936, 60.00121], [20.5104, 59.15546], [19.84909, 57.57876], [22.80496, 57.87798], [23.20055, 57.56697], [24.26221, 57.91787], [24.3579, 57.87471], [25.19484, 58.0831], [25.28237, 57.98539], [25.29581, 58.08288], [25.73499, 57.90193], [26.05949, 57.84744], [26.0324, 57.79037], [26.02456, 57.78342], [26.027, 57.78158], [26.0266, 57.77441], [26.02069, 57.77169], [26.02415, 57.76865], [26.03332, 57.7718], [26.0543, 57.76105], [26.08098, 57.76619], [26.2029, 57.7206], [26.1866, 57.6849], [26.29253, 57.59244], [26.46527, 57.56885], [26.54675, 57.51813], [26.90364, 57.62823], [27.34698, 57.52242], [27.31919, 57.57672], [27.40393, 57.62125], [27.3746, 57.66834], [27.52615, 57.72843], [27.50171, 57.78842], [27.56689, 57.83356], [27.78526, 57.83963], [27.81841, 57.89244], [27.67282, 57.92627], [27.62393, 58.09462], [27.48541, 58.22615], [27.55489, 58.39525], [27.36366, 58.78381], [27.74429, 58.98351], [27.80482, 59.1116], [27.87978, 59.18097], [27.90911, 59.24353], [28.00689, 59.28351], [28.14215, 59.28934], [28.19284, 59.35791], [28.20537, 59.36491], [28.21137, 59.38058], [28.19061, 59.39962], [28.04187, 59.47017], [27.85643, 59.58538], [26.90044, 59.63819], [26.32936, 60.00121]]]]
24856 groups: ["015", "002", "UN"],
24857 callingCodes: ["20"]
24860 type: "MultiPolygon",
24861 coordinates: [[[[33.62659, 31.82938], [26.92891, 33.39516], [24.8458, 31.39877], [25.01077, 30.73861], [24.71117, 30.17441], [24.99968, 29.24574], [24.99885, 21.99535], [33.17563, 22.00405], [34.0765, 22.00501], [37.8565, 22.00903], [34.4454, 27.91479], [34.8812, 29.36878], [34.92298, 29.45305], [34.26742, 31.21998], [34.24012, 31.29591], [34.23572, 31.2966], [34.21853, 31.32363], [34.052, 31.46619], [33.62659, 31.82938]]]]
24870 nameEn: "Western Sahara",
24871 groups: ["015", "002"],
24872 callingCodes: ["212"]
24875 type: "MultiPolygon",
24876 coordinates: [[[[-8.66879, 27.6666], [-8.77527, 27.66663], [-8.71787, 26.9898], [-9.08698, 26.98639], [-9.56957, 26.90042], [-9.81998, 26.71379], [-10.68417, 26.90984], [-11.35695, 26.8505], [-11.23622, 26.72023], [-11.38635, 26.611], [-11.62052, 26.05229], [-12.06001, 26.04442], [-12.12281, 25.13682], [-12.92147, 24.39502], [-13.00628, 24.01923], [-13.75627, 23.77231], [-14.10361, 22.75501], [-14.1291, 22.41636], [-14.48112, 22.00886], [-14.47329, 21.63839], [-14.78487, 21.36587], [-16.44269, 21.39745], [-16.9978, 21.36239], [-17.02707, 21.34022], [-17.21511, 21.34226], [-17.35589, 20.80492], [-17.0471, 20.76408], [-17.0695, 20.85742], [-17.06781, 20.92697], [-17.0396, 20.9961], [-17.0357, 21.05368], [-16.99806, 21.12142], [-16.95474, 21.33997], [-13.01525, 21.33343], [-13.08438, 22.53866], [-13.15313, 22.75649], [-13.10753, 22.89493], [-13.00412, 23.02297], [-12.5741, 23.28975], [-12.36213, 23.3187], [-12.14969, 23.41935], [-12.00251, 23.4538], [-12.0002, 25.9986], [-8.66721, 25.99918], [-8.66674, 27.31569], [-8.66879, 27.6666]]]]
24886 groups: ["014", "202", "002", "UN"],
24887 callingCodes: ["291"]
24890 type: "MultiPolygon",
24891 coordinates: [[[[40.99158, 15.81743], [39.63762, 18.37348], [38.57727, 17.98125], [38.45916, 17.87167], [38.37133, 17.66269], [38.13362, 17.53906], [37.50967, 17.32199], [37.42694, 17.04041], [36.99777, 17.07172], [36.92193, 16.23451], [36.76371, 15.80831], [36.69761, 15.75323], [36.54276, 15.23478], [36.44337, 15.14963], [36.54376, 14.25597], [36.56536, 14.26177], [36.55659, 14.28237], [36.63364, 14.31172], [36.85787, 14.32201], [37.01622, 14.2561], [37.09486, 14.27155], [37.13206, 14.40746], [37.3106, 14.44657], [37.47319, 14.2149], [37.528, 14.18413], [37.91287, 14.89447], [38.0364, 14.72745], [38.25562, 14.67287], [38.3533, 14.51323], [38.45748, 14.41445], [38.78306, 14.4754], [38.98058, 14.54895], [39.02834, 14.63717], [39.16074, 14.65187], [39.14772, 14.61827], [39.19547, 14.56996], [39.23888, 14.56365], [39.26927, 14.48801], [39.2302, 14.44598], [39.2519, 14.40393], [39.37685, 14.54402], [39.52756, 14.49011], [39.50585, 14.55735], [39.58182, 14.60987], [39.76632, 14.54264], [39.9443, 14.41024], [40.07236, 14.54264], [40.14649, 14.53969], [40.21128, 14.39342], [40.25686, 14.41445], [40.9167, 14.11152], [41.25097, 13.60787], [41.62864, 13.38626], [42.05841, 12.80912], [42.21469, 12.75832], [42.2798, 12.6355], [42.4037, 12.46478], [42.46941, 12.52661], [42.6957, 12.36201], [42.7996, 12.42629], [42.86195, 12.58747], [43.29075, 12.79154], [40.99158, 15.81743]]]]
24910 nameEn: "Ethiopia",
24911 groups: ["014", "202", "002", "UN"],
24912 callingCodes: ["251"]
24915 type: "MultiPolygon",
24916 coordinates: [[[[42.4037, 12.46478], [42.2798, 12.6355], [42.21469, 12.75832], [42.05841, 12.80912], [41.62864, 13.38626], [41.25097, 13.60787], [40.9167, 14.11152], [40.25686, 14.41445], [40.21128, 14.39342], [40.14649, 14.53969], [40.07236, 14.54264], [39.9443, 14.41024], [39.76632, 14.54264], [39.58182, 14.60987], [39.50585, 14.55735], [39.52756, 14.49011], [39.37685, 14.54402], [39.2519, 14.40393], [39.2302, 14.44598], [39.26927, 14.48801], [39.23888, 14.56365], [39.19547, 14.56996], [39.14772, 14.61827], [39.16074, 14.65187], [39.02834, 14.63717], [38.98058, 14.54895], [38.78306, 14.4754], [38.45748, 14.41445], [38.3533, 14.51323], [38.25562, 14.67287], [38.0364, 14.72745], [37.91287, 14.89447], [37.528, 14.18413], [37.47319, 14.2149], [37.3106, 14.44657], [37.13206, 14.40746], [37.09486, 14.27155], [37.01622, 14.2561], [36.85787, 14.32201], [36.63364, 14.31172], [36.55659, 14.28237], [36.56536, 14.26177], [36.54376, 14.25597], [36.44653, 13.95666], [36.48824, 13.83954], [36.38993, 13.56459], [36.24545, 13.36759], [36.13374, 12.92665], [36.16651, 12.88019], [36.14268, 12.70879], [36.01458, 12.72478], [35.70476, 12.67101], [35.24302, 11.91132], [35.11492, 11.85156], [35.05832, 11.71158], [35.09556, 11.56278], [34.95704, 11.24448], [35.01215, 11.19626], [34.93172, 10.95946], [34.97789, 10.91559], [34.97491, 10.86147], [34.86916, 10.78832], [34.86618, 10.74588], [34.77532, 10.69027], [34.77383, 10.74588], [34.59062, 10.89072], [34.4372, 10.781], [34.2823, 10.53508], [34.34783, 10.23914], [34.32102, 10.11599], [34.22718, 10.02506], [34.20484, 9.9033], [34.13186, 9.7492], [34.08717, 9.55243], [34.10229, 9.50238], [34.14304, 9.04654], [34.14453, 8.60204], [34.01346, 8.50041], [33.89579, 8.4842], [33.87195, 8.41938], [33.71407, 8.3678], [33.66938, 8.44442], [33.54575, 8.47094], [33.3119, 8.45474], [33.19721, 8.40317], [33.1853, 8.29264], [33.18083, 8.13047], [33.08401, 8.05822], [33.0006, 7.90333], [33.04944, 7.78989], [33.24637, 7.77939], [33.32531, 7.71297], [33.44745, 7.7543], [33.71407, 7.65983], [33.87642, 7.5491], [34.02984, 7.36449], [34.03878, 7.27437], [34.01495, 7.25664], [34.19369, 7.12807], [34.19369, 7.04382], [34.35753, 6.91963], [34.47669, 6.91076], [34.53925, 6.82794], [34.53776, 6.74808], [34.65096, 6.72589], [34.77459, 6.5957], [34.87736, 6.60161], [35.01738, 6.46991], [34.96227, 6.26415], [35.00546, 5.89387], [35.12611, 5.68937], [35.13058, 5.62118], [35.31188, 5.50106], [35.29938, 5.34042], [35.50792, 5.42431], [35.8576, 5.33413], [35.81968, 5.10757], [35.82118, 4.77382], [35.9419, 4.61933], [35.95449, 4.53244], [36.03924, 4.44406], [36.84474, 4.44518], [37.07724, 4.33503], [38.14168, 3.62487], [38.45812, 3.60445], [38.52336, 3.62551], [38.91938, 3.51198], [39.07736, 3.5267], [39.19954, 3.47834], [39.49444, 3.45521], [39.51551, 3.40895], [39.55132, 3.39634], [39.58339, 3.47434], [39.76808, 3.67058], [39.86043, 3.86974], [40.77498, 4.27683], [41.1754, 3.94079], [41.89488, 3.97375], [42.07619, 4.17667], [42.55853, 4.20518], [42.84526, 4.28357], [42.97746, 4.44032], [43.04177, 4.57923], [43.40263, 4.79289], [44.02436, 4.9451], [44.98104, 4.91821], [47.97917, 8.00124], [47.92477, 8.00111], [46.99339, 7.9989], [44.19222, 8.93028], [43.32613, 9.59205], [43.23518, 9.84605], [43.0937, 9.90579], [42.87643, 10.18441], [42.69452, 10.62672], [42.95776, 10.98533], [42.79037, 10.98493], [42.75111, 11.06992], [42.62989, 11.09711], [42.42669, 10.98493], [42.13691, 10.97586], [42.06302, 10.92599], [41.80056, 10.97127], [41.8096, 11.33606], [41.77727, 11.49902], [41.82878, 11.72361], [41.95461, 11.81157], [42.4037, 12.46478]]]]
24924 nameEn: "European Union",
24926 isoStatus: "excRes"
24948 groups: ["054", "009", "UN"],
24950 callingCodes: ["679"]
24953 type: "MultiPolygon",
24954 coordinates: [[[[174.245, -23.1974], [179.99999, -22.5], [179.99999, -11.5], [174, -11.5], [174.245, -23.1974]]], [[[-176.76826, -14.95183], [-180, -14.96041], [-180, -22.90585], [-176.74538, -22.89767], [-176.76826, -14.95183]]]]
24963 nameEn: "Falkland Islands",
24965 groups: ["BOTS", "005", "419", "019", "UN"],
24967 roadSpeedUnit: "mph",
24968 roadHeightUnit: "ft",
24969 callingCodes: ["500"]
24972 type: "MultiPolygon",
24973 coordinates: [[[[-63.67376, -55.11859], [-54.56126, -51.26248], [-61.26735, -50.63919], [-63.67376, -55.11859]]]]
24982 nameEn: "Federated States of Micronesia",
24983 groups: ["057", "009", "UN"],
24984 roadSpeedUnit: "mph",
24985 roadHeightUnit: "ft",
24986 callingCodes: ["691"]
24989 type: "MultiPolygon",
24990 coordinates: [[[[138.20583, 13.3783], [136.27107, 6.73747], [156.88247, -1.39237], [165.19726, 6.22546], [138.20583, 13.3783]]]]
24999 nameEn: "Faroe Islands",
25001 groups: ["154", "150", "UN"],
25002 callingCodes: ["298"]
25005 type: "MultiPolygon",
25006 coordinates: [[[[-8.51774, 62.35338], [-6.51083, 60.95272], [-5.70102, 62.77194], [-8.51774, 62.35338]]]]
25024 wikidata: "Q212429",
25025 nameEn: "Metropolitan France",
25027 groups: ["EU", "155", "150", "UN"],
25028 isoStatus: "excRes",
25029 callingCodes: ["33"]
25032 type: "MultiPolygon",
25033 coordinates: [[[[2.55904, 51.07014], [2.18458, 51.52087], [1.17405, 50.74239], [-2.02963, 49.91866], [-2.09454, 49.46288], [-1.83944, 49.23037], [-2.00491, 48.86706], [-2.65349, 49.15373], [-6.28985, 48.93406], [-1.81005, 43.59738], [-1.77289, 43.38957], [-1.79319, 43.37497], [-1.78332, 43.36399], [-1.78714, 43.35476], [-1.77068, 43.34396], [-1.75334, 43.34107], [-1.75079, 43.3317], [-1.7397, 43.32979], [-1.73074, 43.29481], [-1.69407, 43.31378], [-1.62481, 43.30726], [-1.63052, 43.28591], [-1.61341, 43.25269], [-1.57674, 43.25269], [-1.55963, 43.28828], [-1.50992, 43.29481], [-1.45289, 43.27049], [-1.40942, 43.27272], [-1.3758, 43.24511], [-1.41562, 43.12815], [-1.47555, 43.08372], [-1.44067, 43.047], [-1.35272, 43.02658], [-1.34419, 43.09665], [-1.32209, 43.1127], [-1.27118, 43.11961], [-1.30052, 43.09581], [-1.30531, 43.06859], [-1.25244, 43.04164], [-1.22881, 43.05534], [-1.10333, 43.0059], [-1.00963, 42.99279], [-0.97133, 42.96239], [-0.81652, 42.95166], [-0.75478, 42.96916], [-0.72037, 42.92541], [-0.73422, 42.91228], [-0.72608, 42.89318], [-0.69837, 42.87945], [-0.67637, 42.88303], [-0.55497, 42.77846], [-0.50863, 42.82713], [-0.44334, 42.79939], [-0.41319, 42.80776], [-0.38833, 42.80132], [-0.3122, 42.84788], [-0.17939, 42.78974], [-0.16141, 42.79535], [-0.10519, 42.72761], [-0.02468, 42.68513], [0.17569, 42.73424], [0.25336, 42.7174], [0.29407, 42.67431], [0.36251, 42.72282], [0.40214, 42.69779], [0.67873, 42.69458], [0.65421, 42.75872], [0.66121, 42.84021], [0.711, 42.86372], [0.93089, 42.79154], [0.96166, 42.80629], [0.98292, 42.78754], [1.0804, 42.78569], [1.15928, 42.71407], [1.35562, 42.71944], [1.44197, 42.60217], [1.47986, 42.61346], [1.46718, 42.63296], [1.48043, 42.65203], [1.50867, 42.64483], [1.55418, 42.65669], [1.60085, 42.62703], [1.63485, 42.62957], [1.6625, 42.61982], [1.68267, 42.62533], [1.73452, 42.61515], [1.72588, 42.59098], [1.7858, 42.57698], [1.73683, 42.55492], [1.72515, 42.50338], [1.76335, 42.48863], [1.83037, 42.48395], [1.88853, 42.4501], [1.93663, 42.45439], [1.94292, 42.44316], [1.94061, 42.43333], [1.94084, 42.43039], [1.9574, 42.42401], [1.96482, 42.37787], [2.00488, 42.35399], [2.06241, 42.35906], [2.11621, 42.38393], [2.12789, 42.41291], [2.16599, 42.42314], [2.20578, 42.41633], [2.25551, 42.43757], [2.38504, 42.39977], [2.43299, 42.39423], [2.43508, 42.37568], [2.48457, 42.33933], [2.54382, 42.33406], [2.55516, 42.35351], [2.57934, 42.35808], [2.6747, 42.33974], [2.65311, 42.38771], [2.72056, 42.42298], [2.75497, 42.42578], [2.77464, 42.41046], [2.84335, 42.45724], [2.85675, 42.45444], [2.86983, 42.46843], [2.88413, 42.45938], [2.92107, 42.4573], [2.94283, 42.48174], [2.96518, 42.46692], [3.03734, 42.47363], [3.08167, 42.42748], [3.10027, 42.42621], [3.11379, 42.43646], [3.17156, 42.43545], [3.75438, 42.33445], [7.60802, 41.05927], [10.09675, 41.44089], [9.56115, 43.20816], [7.50102, 43.51859], [7.42422, 43.72209], [7.40903, 43.7296], [7.41113, 43.73156], [7.41291, 43.73168], [7.41298, 43.73311], [7.41233, 43.73439], [7.42062, 43.73977], [7.42299, 43.74176], [7.42443, 43.74087], [7.42809, 43.74396], [7.43013, 43.74895], [7.43624, 43.75014], [7.43708, 43.75197], [7.4389, 43.75151], [7.4379, 43.74963], [7.47823, 43.73341], [7.53006, 43.78405], [7.50423, 43.84345], [7.49355, 43.86551], [7.51162, 43.88301], [7.56075, 43.89932], [7.56858, 43.94506], [7.60771, 43.95772], [7.65266, 43.9763], [7.66848, 43.99943], [7.6597, 44.03009], [7.72508, 44.07578], [7.66878, 44.12795], [7.68694, 44.17487], [7.63245, 44.17877], [7.62155, 44.14881], [7.36364, 44.11882], [7.34547, 44.14359], [7.27827, 44.1462], [7.16929, 44.20352], [7.00764, 44.23736], [6.98221, 44.28289], [6.89171, 44.36637], [6.88784, 44.42043], [6.94504, 44.43112], [6.86233, 44.49834], [6.85507, 44.53072], [6.96042, 44.62129], [6.95133, 44.66264], [7.00582, 44.69364], [7.07484, 44.68073], [7.00401, 44.78782], [7.02217, 44.82519], [6.93499, 44.8664], [6.90774, 44.84322], [6.75518, 44.89915], [6.74519, 44.93661], [6.74791, 45.01939], [6.66981, 45.02324], [6.62803, 45.11175], [6.7697, 45.16044], [6.85144, 45.13226], [6.96706, 45.20841], [7.07074, 45.21228], [7.13115, 45.25386], [7.10572, 45.32924], [7.18019, 45.40071], [7.00037, 45.509], [6.98948, 45.63869], [6.80785, 45.71864], [6.80785, 45.83265], [6.95315, 45.85163], [7.04151, 45.92435], [7.00946, 45.9944], [6.93862, 46.06502], [6.87868, 46.03855], [6.89321, 46.12548], [6.78968, 46.14058], [6.86052, 46.28512], [6.77152, 46.34784], [6.8024, 46.39171], [6.82312, 46.42661], [6.53358, 46.45431], [6.25432, 46.3632], [6.21981, 46.31304], [6.24826, 46.30175], [6.25137, 46.29014], [6.23775, 46.27822], [6.24952, 46.26255], [6.26749, 46.24745], [6.29474, 46.26221], [6.31041, 46.24417], [6.29663, 46.22688], [6.27694, 46.21566], [6.26007, 46.21165], [6.24821, 46.20531], [6.23913, 46.20511], [6.23544, 46.20714], [6.22175, 46.20045], [6.22222, 46.19888], [6.21844, 46.19837], [6.21603, 46.19507], [6.21273, 46.19409], [6.21114, 46.1927], [6.20539, 46.19163], [6.19807, 46.18369], [6.19552, 46.18401], [6.18707, 46.17999], [6.18871, 46.16644], [6.18116, 46.16187], [6.15305, 46.15194], [6.13397, 46.1406], [6.09926, 46.14373], [6.09199, 46.15191], [6.07491, 46.14879], [6.05203, 46.15191], [6.04564, 46.14031], [6.03614, 46.13712], [6.01791, 46.14228], [5.9871, 46.14499], [5.97893, 46.13303], [5.95781, 46.12925], [5.9641, 46.14412], [5.97508, 46.15863], [5.98188, 46.17392], [5.98846, 46.17046], [5.99573, 46.18587], [5.96515, 46.19638], [5.97542, 46.21525], [6.02461, 46.23313], [6.03342, 46.2383], [6.04602, 46.23127], [6.05029, 46.23518], [6.0633, 46.24583], [6.07072, 46.24085], [6.08563, 46.24651], [6.10071, 46.23772], [6.12446, 46.25059], [6.11926, 46.2634], [6.1013, 46.28512], [6.11697, 46.29547], [6.1198, 46.31157], [6.13876, 46.33844], [6.15738, 46.3491], [6.16987, 46.36759], [6.15985, 46.37721], [6.15016, 46.3778], [6.09926, 46.40768], [6.06407, 46.41676], [6.08427, 46.44305], [6.07269, 46.46244], [6.1567, 46.54402], [6.11084, 46.57649], [6.27135, 46.68251], [6.38351, 46.73171], [6.45209, 46.77502], [6.43216, 46.80336], [6.46456, 46.88865], [6.43341, 46.92703], [6.71531, 47.0494], [6.68823, 47.06616], [6.76788, 47.1208], [6.8489, 47.15933], [6.9508, 47.24338], [6.95108, 47.26428], [6.94316, 47.28747], [7.05305, 47.33304], [7.0564, 47.35134], [7.03125, 47.36996], [6.87959, 47.35335], [6.88542, 47.37262], [6.93744, 47.40714], [6.93953, 47.43388], [7.0024, 47.45264], [6.98425, 47.49432], [7.0231, 47.50522], [7.07425, 47.48863], [7.12781, 47.50371], [7.16249, 47.49025], [7.19583, 47.49455], [7.17026, 47.44312], [7.24669, 47.4205], [7.33526, 47.44186], [7.35603, 47.43432], [7.40308, 47.43638], [7.43088, 47.45846], [7.4462, 47.46264], [7.4583, 47.47216], [7.42923, 47.48628], [7.43356, 47.49712], [7.47534, 47.47932], [7.51076, 47.49651], [7.49804, 47.51798], [7.5229, 47.51644], [7.53199, 47.5284], [7.51904, 47.53515], [7.50588, 47.52856], [7.49691, 47.53821], [7.50873, 47.54546], [7.51723, 47.54578], [7.52831, 47.55347], [7.53634, 47.55553], [7.55652, 47.56779], [7.55689, 47.57232], [7.56548, 47.57617], [7.56684, 47.57785], [7.58386, 47.57536], [7.58945, 47.59017], [7.59301, 47.60058], [7.58851, 47.60794], [7.57423, 47.61628], [7.5591, 47.63849], [7.53384, 47.65115], [7.52067, 47.66437], [7.51915, 47.68335], [7.51266, 47.70197], [7.53722, 47.71635], [7.54761, 47.72912], [7.52921, 47.77747], [7.55673, 47.87371], [7.62302, 47.97898], [7.56966, 48.03265], [7.57137, 48.12292], [7.6648, 48.22219], [7.69022, 48.30018], [7.74562, 48.32736], [7.73109, 48.39192], [7.76833, 48.48945], [7.80647, 48.51239], [7.80167, 48.54758], [7.80057, 48.5857], [7.84098, 48.64217], [7.89002, 48.66317], [7.96812, 48.72491], [7.96994, 48.75606], [8.01534, 48.76085], [8.0326, 48.79017], [8.06802, 48.78957], [8.10253, 48.81829], [8.12813, 48.87985], [8.19989, 48.95825], [8.20031, 48.95856], [8.22604, 48.97352], [8.14189, 48.97833], [7.97783, 49.03161], [7.93641, 49.05544], [7.86386, 49.03499], [7.79557, 49.06583], [7.75948, 49.04562], [7.63618, 49.05428], [7.62575, 49.07654], [7.56416, 49.08136], [7.53012, 49.09818], [7.49172, 49.13915], [7.49473, 49.17], [7.44455, 49.16765], [7.44052, 49.18354], [7.3662, 49.17308], [7.35995, 49.14399], [7.3195, 49.14231], [7.29514, 49.11426], [7.23473, 49.12971], [7.1593, 49.1204], [7.1358, 49.1282], [7.12504, 49.14253], [7.10384, 49.13787], [7.10715, 49.15631], [7.07859, 49.15031], [7.09007, 49.13094], [7.07162, 49.1255], [7.06642, 49.11415], [7.05548, 49.11185], [7.04843, 49.11422], [7.04409, 49.12123], [7.04662, 49.13724], [7.03178, 49.15734], [7.0274, 49.17042], [7.03459, 49.19096], [7.01318, 49.19018], [6.97273, 49.2099], [6.95963, 49.203], [6.94028, 49.21641], [6.93831, 49.2223], [6.91875, 49.22261], [6.89298, 49.20863], [6.85939, 49.22376], [6.83555, 49.21249], [6.85119, 49.20038], [6.85016, 49.19354], [6.86225, 49.18185], [6.84703, 49.15734], [6.83385, 49.15162], [6.78265, 49.16793], [6.73765, 49.16375], [6.71137, 49.18808], [6.73256, 49.20486], [6.71843, 49.2208], [6.69274, 49.21661], [6.66583, 49.28065], [6.60186, 49.31055], [6.572, 49.35027], [6.58807, 49.35358], [6.60091, 49.36864], [6.533, 49.40748], [6.55404, 49.42464], [6.42432, 49.47683], [6.40274, 49.46546], [6.39168, 49.4667], [6.38352, 49.46463], [6.36778, 49.46937], [6.3687, 49.4593], [6.28818, 49.48465], [6.27875, 49.503], [6.25029, 49.50609], [6.2409, 49.51408], [6.19543, 49.50536], [6.17386, 49.50934], [6.15366, 49.50226], [6.16115, 49.49297], [6.14321, 49.48796], [6.12814, 49.49365], [6.12346, 49.4735], [6.10325, 49.4707], [6.09845, 49.46351], [6.10072, 49.45268], [6.08373, 49.45594], [6.07887, 49.46399], [6.05553, 49.46663], [6.04176, 49.44801], [6.02743, 49.44845], [6.02648, 49.45451], [5.97693, 49.45513], [5.96876, 49.49053], [5.94224, 49.49608], [5.94128, 49.50034], [5.86571, 49.50015], [5.83389, 49.52152], [5.83467, 49.52717], [5.84466, 49.53027], [5.83648, 49.5425], [5.81664, 49.53775], [5.80871, 49.5425], [5.81838, 49.54777], [5.79195, 49.55228], [5.77435, 49.56298], [5.7577, 49.55915], [5.75649, 49.54321], [5.64505, 49.55146], [5.60909, 49.51228], [5.55001, 49.52729], [5.46541, 49.49825], [5.46734, 49.52648], [5.43713, 49.5707], [5.3974, 49.61596], [5.34837, 49.62889], [5.33851, 49.61599], [5.3137, 49.61225], [5.30214, 49.63055], [5.33039, 49.6555], [5.31465, 49.66846], [5.26232, 49.69456], [5.14545, 49.70287], [5.09249, 49.76193], [4.96714, 49.79872], [4.85464, 49.78995], [4.86965, 49.82271], [4.85134, 49.86457], [4.88529, 49.9236], [4.78827, 49.95609], [4.8382, 50.06738], [4.88602, 50.15182], [4.83279, 50.15331], [4.82438, 50.16878], [4.75237, 50.11314], [4.70064, 50.09384], [4.68695, 49.99685], [4.5414, 49.96911], [4.51098, 49.94659], [4.43488, 49.94122], [4.35051, 49.95315], [4.31963, 49.97043], [4.20532, 49.95803], [4.14239, 49.98034], [4.13508, 50.01976], [4.16294, 50.04719], [4.23101, 50.06945], [4.20147, 50.13535], [4.13561, 50.13078], [4.16014, 50.19239], [4.15524, 50.21103], [4.21945, 50.25539], [4.20651, 50.27333], [4.17861, 50.27443], [4.17347, 50.28838], [4.15524, 50.2833], [4.16808, 50.25786], [4.13665, 50.25609], [4.11954, 50.30425], [4.10957, 50.30234], [4.10237, 50.31247], [4.0689, 50.3254], [4.0268, 50.35793], [3.96771, 50.34989], [3.90781, 50.32814], [3.84314, 50.35219], [3.73911, 50.34809], [3.70987, 50.3191], [3.71009, 50.30305], [3.66976, 50.34563], [3.65709, 50.36873], [3.67262, 50.38663], [3.67494, 50.40239], [3.66153, 50.45165], [3.64426, 50.46275], [3.61014, 50.49568], [3.58361, 50.49049], [3.5683, 50.50192], [3.49509, 50.48885], [3.51564, 50.5256], [3.47385, 50.53397], [3.44629, 50.51009], [3.37693, 50.49538], [3.28575, 50.52724], [3.2729, 50.60718], [3.23951, 50.6585], [3.264, 50.67668], [3.2536, 50.68977], [3.26141, 50.69151], [3.26063, 50.70086], [3.24593, 50.71389], [3.22042, 50.71019], [3.20845, 50.71662], [3.19017, 50.72569], [3.20064, 50.73547], [3.18811, 50.74025], [3.18339, 50.74981], [3.16476, 50.76843], [3.15017, 50.79031], [3.1257, 50.78603], [3.11987, 50.79188], [3.11206, 50.79416], [3.10614, 50.78303], [3.09163, 50.77717], [3.04314, 50.77674], [3.00537, 50.76588], [2.96778, 50.75242], [2.95019, 50.75138], [2.90873, 50.702], [2.91036, 50.6939], [2.90069, 50.69263], [2.88504, 50.70656], [2.87937, 50.70298], [2.86985, 50.7033], [2.8483, 50.72276], [2.81056, 50.71773], [2.71165, 50.81295], [2.63331, 50.81457], [2.59093, 50.91751], [2.63074, 50.94746], [2.57551, 51.00326], [2.55904, 51.07014]], [[1.99838, 42.44682], [1.98378, 42.44697], [1.96125, 42.45364], [1.95606, 42.45785], [1.96215, 42.47854], [1.97003, 42.48081], [1.97227, 42.48487], [1.97697, 42.48568], [1.98022, 42.49569], [1.98916, 42.49351], [1.99766, 42.4858], [1.98579, 42.47486], [1.99216, 42.46208], [2.01564, 42.45171], [1.99838, 42.44682]]]]
25043 groups: ["017", "202", "002", "UN"],
25044 callingCodes: ["241"]
25047 type: "MultiPolygon",
25048 coordinates: [[[[13.29457, 2.16106], [13.28534, 2.25716], [11.37116, 2.29975], [11.3561, 2.17217], [11.35307, 1.00251], [9.79648, 1.0019], [9.75065, 1.06753], [9.66433, 1.06723], [7.24416, -0.64092], [10.75913, -4.39519], [11.12647, -3.94169], [11.22301, -3.69888], [11.48764, -3.51089], [11.57949, -3.52798], [11.68608, -3.68942], [11.87083, -3.71571], [11.92719, -3.62768], [11.8318, -3.5812], [11.96554, -3.30267], [11.70227, -3.17465], [11.70558, -3.0773], [11.80365, -3.00424], [11.64798, -2.81146], [11.5359, -2.85654], [11.64487, -2.61865], [11.57637, -2.33379], [11.74605, -2.39936], [11.96866, -2.33559], [12.04895, -2.41704], [12.47925, -2.32626], [12.44656, -1.92025], [12.61312, -1.8129], [12.82172, -1.91091], [13.02759, -2.33098], [13.47977, -2.43224], [13.75884, -2.09293], [13.92073, -2.35581], [13.85846, -2.46935], [14.10442, -2.49268], [14.23829, -2.33715], [14.16202, -2.23916], [14.23518, -2.15671], [14.25932, -1.97624], [14.41838, -1.89412], [14.52569, -0.57818], [14.41887, -0.44799], [14.2165, -0.38261], [14.06862, -0.20826], [13.90632, -0.2287], [13.88648, 0.26652], [14.10909, 0.58563], [14.26066, 0.57255], [14.48179, 0.9152], [14.25186, 1.39842], [13.89582, 1.4261], [13.15519, 1.23368], [13.25447, 1.32339], [13.13461, 1.57238], [13.29457, 2.16106]]]]
25058 nameEn: "United Kingdom",
25071 groups: ["029", "003", "419", "019", "UN"],
25073 roadSpeedUnit: "mph",
25074 callingCodes: ["1 473"]
25077 type: "MultiPolygon",
25078 coordinates: [[[[-62.64026, 12.69984], [-61.77886, 11.36496], [-59.94058, 12.34011], [-62.64026, 12.69984]]]]
25088 groups: ["145", "142", "UN"],
25089 callingCodes: ["995"]
25092 type: "MultiPolygon",
25093 coordinates: [[[[46.42738, 41.91323], [45.61676, 42.20768], [45.78692, 42.48358], [45.36501, 42.55268], [45.15318, 42.70598], [44.88754, 42.74934], [44.80941, 42.61277], [44.70002, 42.74679], [44.54202, 42.75699], [43.95517, 42.55396], [43.73119, 42.62043], [43.81453, 42.74297], [43.0419, 43.02413], [43.03322, 43.08883], [42.75889, 43.19651], [42.66667, 43.13917], [42.40563, 43.23226], [41.64935, 43.22331], [40.65957, 43.56212], [40.10657, 43.57344], [40.04445, 43.47776], [40.03312, 43.44262], [40.01007, 43.42411], [40.01552, 43.42025], [40.00853, 43.40578], [40.0078, 43.38551], [39.81147, 43.06294], [40.89217, 41.72528], [41.54366, 41.52185], [41.7148, 41.4932], [41.7124, 41.47417], [41.81939, 41.43621], [41.95134, 41.52466], [42.26387, 41.49346], [42.51772, 41.43606], [42.59202, 41.58183], [42.72794, 41.59714], [42.84471, 41.58912], [42.78995, 41.50126], [42.84899, 41.47265], [42.8785, 41.50516], [43.02956, 41.37891], [43.21707, 41.30331], [43.13373, 41.25503], [43.1945, 41.25242], [43.23096, 41.17536], [43.36118, 41.2028], [43.44973, 41.17666], [43.4717, 41.12611], [43.67712, 41.13398], [43.74717, 41.1117], [43.84835, 41.16329], [44.16591, 41.19141], [44.18148, 41.24644], [44.32139, 41.2079], [44.34337, 41.20312], [44.34417, 41.2382], [44.46791, 41.18204], [44.59322, 41.1933], [44.61462, 41.24018], [44.72814, 41.20338], [44.82084, 41.21513], [44.87887, 41.20195], [44.89911, 41.21366], [44.84358, 41.23088], [44.81749, 41.23488], [44.80053, 41.25949], [44.81437, 41.30371], [44.93493, 41.25685], [45.0133, 41.29747], [45.09867, 41.34065], [45.1797, 41.42231], [45.26285, 41.46433], [45.31352, 41.47168], [45.4006, 41.42402], [45.45973, 41.45898], [45.68389, 41.3539], [45.71035, 41.36208], [45.75705, 41.35157], [45.69946, 41.29545], [45.80842, 41.2229], [45.95786, 41.17956], [46.13221, 41.19479], [46.27698, 41.19011], [46.37661, 41.10805], [46.456, 41.09984], [46.48558, 41.0576], [46.55096, 41.1104], [46.63969, 41.09515], [46.66148, 41.20533], [46.72375, 41.28609], [46.63658, 41.37727], [46.4669, 41.43331], [46.40307, 41.48464], [46.33925, 41.4963], [46.29794, 41.5724], [46.34126, 41.57454], [46.34039, 41.5947], [46.3253, 41.60912], [46.28182, 41.60089], [46.26531, 41.63339], [46.24429, 41.59883], [46.19759, 41.62327], [46.17891, 41.72094], [46.20538, 41.77205], [46.23962, 41.75811], [46.30863, 41.79133], [46.3984, 41.84399], [46.42738, 41.91323]]]]
25102 nameEn: "French Guiana",
25104 groups: ["Q3320166", "EU", "005", "419", "019", "UN"],
25105 callingCodes: ["594"]
25108 type: "MultiPolygon",
25109 coordinates: [[[[-51.35485, 4.8383], [-53.7094, 6.2264], [-54.01074, 5.68785], [-54.01877, 5.52789], [-54.26916, 5.26909], [-54.4717, 4.91964], [-54.38444, 4.13222], [-54.19367, 3.84387], [-54.05128, 3.63557], [-53.98914, 3.627], [-53.9849, 3.58697], [-54.28534, 2.67798], [-54.42864, 2.42442], [-54.6084, 2.32856], [-54.16286, 2.10779], [-53.78743, 2.34412], [-52.96539, 2.1881], [-52.6906, 2.37298], [-52.31787, 3.17896], [-51.85573, 3.83427], [-51.82312, 3.85825], [-51.79599, 3.89336], [-51.61983, 4.14596], [-51.63798, 4.51394], [-51.35485, 4.8383]]]]
25117 wikidata: "Q25230",
25118 nameEn: "Bailiwick of Guernsey",
25130 groups: ["011", "202", "002", "UN"],
25131 callingCodes: ["233"]
25134 type: "MultiPolygon",
25135 coordinates: [[[[-0.13493, 11.14075], [-0.27374, 11.17157], [-0.28566, 11.12713], [-0.35955, 11.07801], [-0.38219, 11.12596], [-0.42391, 11.11661], [-0.44298, 11.04292], [-0.61937, 10.91305], [-0.67143, 10.99811], [-2.83373, 11.0067], [-2.94232, 10.64281], [-2.83108, 10.40252], [-2.74174, 9.83172], [-2.76534, 9.56589], [-2.68802, 9.49343], [-2.69814, 9.22717], [-2.77799, 9.04949], [-2.66357, 9.01771], [-2.58243, 8.7789], [-2.49037, 8.20872], [-2.62901, 8.11495], [-2.61232, 8.02645], [-2.67787, 8.02055], [-2.74819, 7.92613], [-2.78395, 7.94974], [-2.79467, 7.86002], [-2.92339, 7.60847], [-2.97822, 7.27165], [-2.95438, 7.23737], [-3.23327, 6.81744], [-3.21954, 6.74407], [-3.25999, 6.62521], [-3.01896, 5.71697], [-2.95323, 5.71865], [-2.96671, 5.6415], [-2.93132, 5.62137], [-2.85378, 5.65156], [-2.76614, 5.60963], [-2.72737, 5.34789], [-2.77625, 5.34621], [-2.73074, 5.1364], [-2.75502, 5.10657], [-2.95261, 5.12477], [-2.96554, 5.10397], [-3.063, 5.13665], [-3.11073, 5.12675], [-3.10675, 5.08515], [-3.34019, 4.17519], [1.07031, 5.15655], [1.27574, 5.93551], [1.19771, 6.11522], [1.19966, 6.17069], [1.09187, 6.17074], [1.05969, 6.22998], [1.03108, 6.24064], [0.99652, 6.33779], [0.89283, 6.33779], [0.71048, 6.53083], [0.74862, 6.56517], [0.63659, 6.63857], [0.6497, 6.73682], [0.58176, 6.76049], [0.57406, 6.80348], [0.52853, 6.82921], [0.56508, 6.92971], [0.52098, 6.94391], [0.52217, 6.9723], [0.59606, 7.01252], [0.65327, 7.31643], [0.62943, 7.41099], [0.57223, 7.39326], [0.52455, 7.45354], [0.51979, 7.58706], [0.58295, 7.62368], [0.62943, 7.85751], [0.58891, 8.12779], [0.6056, 8.13959], [0.61156, 8.18324], [0.5913, 8.19622], [0.63897, 8.25873], [0.73432, 8.29529], [0.64731, 8.48866], [0.47211, 8.59945], [0.37319, 8.75262], [0.52455, 8.87746], [0.45424, 9.04581], [0.56388, 9.40697], [0.49118, 9.48339], [0.36485, 9.49749], [0.33148, 9.44812], [0.25758, 9.42696], [0.2254, 9.47869], [0.31241, 9.50337], [0.30406, 9.521], [0.2409, 9.52335], [0.23851, 9.57389], [0.38153, 9.58682], [0.36008, 9.6256], [0.29334, 9.59387], [0.26712, 9.66437], [0.28261, 9.69022], [0.32313, 9.6491], [0.34816, 9.66907], [0.34816, 9.71607], [0.32075, 9.72781], [0.36366, 10.03309], [0.41252, 10.02018], [0.41371, 10.06361], [0.35293, 10.09412], [0.39584, 10.31112], [0.33028, 10.30408], [0.29453, 10.41546], [0.18846, 10.4096], [0.12886, 10.53149], [-0.05945, 10.63458], [-0.09141, 10.7147], [-0.07327, 10.71845], [-0.07183, 10.76794], [-0.0228, 10.81916], [-0.02685, 10.8783], [-908e-5, 10.91644], [-63e-4, 10.96417], [0.03355, 10.9807], [0.02395, 11.06229], [342e-5, 11.08317], [-514e-5, 11.10763], [-0.0275, 11.11202], [-0.05733, 11.08628], [-0.14462, 11.10811], [-0.13493, 11.14075]]]]
25144 nameEn: "Gibraltar",
25146 groups: ["Q12837", "BOTS", "039", "150", "UN"],
25147 callingCodes: ["350"]
25150 type: "MultiPolygon",
25151 coordinates: [[[[-5.34064, 36.03744], [-5.27801, 36.14942], [-5.33822, 36.15272], [-5.34536, 36.15501], [-5.40526, 36.15488], [-5.34064, 36.03744]]]]
25160 nameEn: "Greenland",
25162 groups: ["Q1451600", "021", "003", "019", "UN"],
25163 callingCodes: ["299"]
25166 type: "MultiPolygon",
25167 coordinates: [[[[-49.33696, 84.57952], [-68.21821, 80.48551], [-77.52957, 77.23408], [-46.37635, 57.3249], [-9.68082, 72.73731], [-5.7106, 84.28058], [-49.33696, 84.57952]]]]
25176 nameEn: "The Gambia",
25177 groups: ["011", "202", "002", "UN"],
25178 callingCodes: ["220"]
25181 type: "MultiPolygon",
25182 coordinates: [[[[-15.14917, 13.57989], [-14.36795, 13.23033], [-13.79409, 13.34472], [-13.8955, 13.59126], [-14.34721, 13.46578], [-14.93719, 13.80173], [-15.36504, 13.79313], [-15.47902, 13.58758], [-17.43598, 13.59273], [-17.43966, 13.04579], [-16.74676, 13.06025], [-16.69343, 13.16791], [-15.80355, 13.16729], [-15.80478, 13.34832], [-15.26908, 13.37768], [-15.14917, 13.57989]]]]
25192 groups: ["011", "202", "002", "UN"],
25193 callingCodes: ["224"]
25196 type: "MultiPolygon",
25197 coordinates: [[[[-11.37536, 12.40788], [-11.46267, 12.44559], [-11.91331, 12.42008], [-12.35415, 12.32758], [-12.87336, 12.51892], [-13.06603, 12.49342], [-13.05296, 12.64003], [-13.70523, 12.68013], [-13.7039, 12.60313], [-13.65089, 12.49515], [-13.64168, 12.42764], [-13.70851, 12.24978], [-13.92745, 12.24077], [-13.94589, 12.16869], [-13.7039, 12.00869], [-13.7039, 11.70195], [-14.09799, 11.63649], [-14.26623, 11.67486], [-14.31513, 11.60713], [-14.51173, 11.49708], [-14.66677, 11.51188], [-14.77786, 11.36323], [-14.95993, 10.99244], [-15.07174, 10.89557], [-15.96748, 10.162], [-14.36218, 8.64107], [-13.29911, 9.04245], [-13.18586, 9.0925], [-13.08953, 9.0409], [-12.94095, 9.26335], [-12.76788, 9.3133], [-12.47254, 9.86834], [-12.24262, 9.92386], [-12.12634, 9.87203], [-11.91023, 9.93927], [-11.89624, 9.99763], [-11.2118, 10.00098], [-10.6534, 9.29919], [-10.74484, 9.07998], [-10.5783, 9.06386], [-10.56197, 8.81225], [-10.47707, 8.67669], [-10.61422, 8.5314], [-10.70565, 8.29235], [-10.63934, 8.35326], [-10.54891, 8.31174], [-10.37257, 8.48941], [-10.27575, 8.48711], [-10.203, 8.47991], [-10.14579, 8.52665], [-10.05375, 8.50697], [-10.05873, 8.42578], [-9.77763, 8.54633], [-9.47415, 8.35195], [-9.50898, 8.18455], [-9.41445, 8.02448], [-9.44928, 7.9284], [-9.35724, 7.74111], [-9.37465, 7.62032], [-9.48161, 7.37122], [-9.41943, 7.41809], [-9.305, 7.42056], [-9.20798, 7.38109], [-9.18311, 7.30461], [-9.09107, 7.1985], [-8.93435, 7.2824], [-8.85724, 7.26019], [-8.8448, 7.35149], [-8.72789, 7.51429], [-8.67814, 7.69428], [-8.55874, 7.70167], [-8.55874, 7.62525], [-8.47114, 7.55676], [-8.4003, 7.6285], [-8.21374, 7.54466], [-8.09931, 7.78626], [-8.13414, 7.87991], [-8.06449, 8.04989], [-7.94695, 8.00925], [-7.99919, 8.11023], [-7.98675, 8.20134], [-8.062, 8.16071], [-8.2411, 8.24196], [-8.22991, 8.48438], [-7.92518, 8.50652], [-7.65653, 8.36873], [-7.69882, 8.66148], [-7.95503, 8.81146], [-7.92518, 8.99332], [-7.73862, 9.08422], [-7.90777, 9.20456], [-7.85056, 9.41812], [-8.03463, 9.39604], [-8.14657, 9.55062], [-8.09434, 9.86936], [-8.15652, 9.94288], [-8.11921, 10.04577], [-8.01225, 10.1021], [-7.97971, 10.17117], [-7.9578, 10.2703], [-8.10207, 10.44649], [-8.22711, 10.41722], [-8.32614, 10.69273], [-8.2667, 10.91762], [-8.35083, 11.06234], [-8.66923, 10.99397], [-8.40058, 11.37466], [-8.80854, 11.66715], [-8.94784, 12.34842], [-9.13689, 12.50875], [-9.38067, 12.48446], [-9.32097, 12.29009], [-9.63938, 12.18312], [-9.714, 12.0226], [-10.30604, 12.24634], [-10.71897, 11.91552], [-10.80355, 12.1053], [-10.99758, 12.24634], [-11.24136, 12.01286], [-11.50006, 12.17826], [-11.37536, 12.40788]]]]
25205 wikidata: "Q17012",
25206 nameEn: "Guadeloupe",
25208 groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
25209 callingCodes: ["590"]
25212 type: "MultiPolygon",
25213 coordinates: [[[[-60.03183, 16.1129], [-61.60296, 16.73066], [-63.00549, 15.26166], [-60.03183, 16.1129]]]]
25222 nameEn: "Equatorial Guinea",
25223 groups: ["017", "202", "002", "UN"],
25224 callingCodes: ["240"]
25227 type: "MultiPolygon",
25228 coordinates: [[[[9.22018, 3.72052], [8.34397, 4.30689], [7.71762, 0.6674], [3.35016, -3.29031], [9.66433, 1.06723], [9.75065, 1.06753], [9.79648, 1.0019], [11.35307, 1.00251], [11.3561, 2.17217], [9.991, 2.16561], [9.90749, 2.20049], [9.89012, 2.20457], [9.84716, 2.24676], [9.83238, 2.29079], [9.83754, 2.32428], [9.82123, 2.35097], [9.81162, 2.33797], [9.22018, 3.72052]]]]
25239 groups: ["EU", "039", "150", "UN"],
25240 callingCodes: ["30"]
25243 type: "MultiPolygon",
25244 coordinates: [[[[26.03489, 40.73051], [26.0754, 40.72772], [26.08638, 40.73214], [26.12495, 40.74283], [26.12854, 40.77339], [26.15685, 40.80709], [26.21351, 40.83298], [26.20856, 40.86048], [26.26169, 40.9168], [26.29441, 40.89119], [26.28623, 40.93005], [26.32259, 40.94042], [26.35894, 40.94292], [26.33297, 40.98388], [26.3606, 41.02027], [26.31928, 41.07386], [26.32259, 41.24929], [26.39861, 41.25053], [26.5209, 41.33993], [26.5837, 41.32131], [26.62997, 41.34613], [26.61767, 41.42281], [26.59742, 41.48058], [26.59196, 41.60491], [26.5209, 41.62592], [26.47958, 41.67037], [26.35957, 41.71149], [26.30255, 41.70925], [26.2654, 41.71544], [26.22888, 41.74139], [26.21325, 41.73223], [26.16841, 41.74858], [26.06148, 41.70345], [26.07083, 41.64584], [26.15146, 41.60828], [26.14328, 41.55496], [26.17951, 41.55409], [26.176, 41.50072], [26.14796, 41.47533], [26.20288, 41.43943], [26.16548, 41.42278], [26.12926, 41.35878], [25.87919, 41.30526], [25.8266, 41.34563], [25.70507, 41.29209], [25.66183, 41.31316], [25.61042, 41.30614], [25.55082, 41.31667], [25.52394, 41.2798], [25.48187, 41.28506], [25.28322, 41.23411], [25.11611, 41.34212], [24.942, 41.38685], [24.90928, 41.40876], [24.86136, 41.39298], [24.82514, 41.4035], [24.8041, 41.34913], [24.71529, 41.41928], [24.61129, 41.42278], [24.52599, 41.56808], [24.30513, 41.51297], [24.27124, 41.57682], [24.18126, 41.51735], [24.10063, 41.54796], [24.06323, 41.53222], [24.06908, 41.46132], [23.96975, 41.44118], [23.91483, 41.47971], [23.89613, 41.45257], [23.80148, 41.43943], [23.76525, 41.40175], [23.67644, 41.41139], [23.63203, 41.37632], [23.52453, 41.40262], [23.40416, 41.39999], [23.33639, 41.36317], [23.31301, 41.40525], [23.22771, 41.37106], [23.21953, 41.33773], [23.1833, 41.31755], [22.93334, 41.34104], [22.81199, 41.3398], [22.76408, 41.32225], [22.74538, 41.16321], [22.71266, 41.13945], [22.65306, 41.18168], [22.62852, 41.14385], [22.58295, 41.11568], [22.5549, 41.13065], [22.42285, 41.11921], [22.26744, 41.16409], [22.17629, 41.15969], [22.1424, 41.12449], [22.06527, 41.15617], [21.90869, 41.09191], [21.91102, 41.04786], [21.7556, 40.92525], [21.69601, 40.9429], [21.57448, 40.86076], [21.53007, 40.90759], [21.41555, 40.9173], [21.35595, 40.87578], [21.25779, 40.86165], [21.21105, 40.8855], [21.15262, 40.85546], [20.97887, 40.85475], [20.98396, 40.79109], [20.95752, 40.76982], [20.98134, 40.76046], [21.05833, 40.66586], [21.03932, 40.56299], [20.96908, 40.51526], [20.94925, 40.46625], [20.83688, 40.47882], [20.7906, 40.42726], [20.78234, 40.35803], [20.71789, 40.27739], [20.67162, 40.09433], [20.62566, 40.0897], [20.61081, 40.07866], [20.55593, 40.06524], [20.51297, 40.08168], [20.48487, 40.06271], [20.42373, 40.06777], [20.37911, 39.99058], [20.31135, 39.99438], [20.41546, 39.82832], [20.41475, 39.81437], [20.38572, 39.78516], [20.30804, 39.81563], [20.29152, 39.80421], [20.31961, 39.72799], [20.27412, 39.69884], [20.22707, 39.67459], [20.22376, 39.64532], [20.15988, 39.652], [20.12956, 39.65805], [20.05189, 39.69112], [20.00957, 39.69227], [19.98042, 39.6504], [19.92466, 39.69533], [19.97622, 39.78684], [19.95905, 39.82857], [19.0384, 40.35325], [19.20409, 39.7532], [22.5213, 33.45682], [29.73302, 35.92555], [29.69611, 36.10365], [29.61805, 36.14179], [29.61002, 36.1731], [29.48192, 36.18377], [29.30783, 36.01033], [28.23708, 36.56812], [27.95037, 36.46155], [27.89482, 36.69898], [27.46117, 36.53789], [27.24613, 36.71622], [27.45627, 36.9008], [27.20312, 36.94571], [27.14757, 37.32], [26.95583, 37.64989], [26.99377, 37.69034], [27.16428, 37.72343], [27.05537, 37.9131], [26.21136, 38.17558], [26.24183, 38.44695], [26.32173, 38.48731], [26.21136, 38.65436], [26.61814, 38.81372], [26.70773, 39.0312], [26.43357, 39.43096], [25.94257, 39.39358], [25.61285, 40.17161], [26.04292, 40.3958], [25.94795, 40.72797], [26.03489, 40.73051]]]]
25252 wikidata: "Q35086",
25253 nameEn: "South Georgia and South Sandwich Islands",
25255 groups: ["BOTS", "005", "419", "019", "UN"],
25257 roadSpeedUnit: "mph",
25258 roadHeightUnit: "ft",
25259 callingCodes: ["500"]
25262 type: "MultiPolygon",
25263 coordinates: [[[[-35.26394, -43.68272], [-53.39656, -59.87088], [-22.31757, -59.85974], [-35.26394, -43.68272]]]]
25272 nameEn: "Guatemala",
25273 groups: ["013", "003", "419", "019", "UN"],
25274 callingCodes: ["502"]
25277 type: "MultiPolygon",
25278 coordinates: [[[[-89.14985, 17.81563], [-90.98678, 17.81655], [-90.99199, 17.25192], [-91.43809, 17.25373], [-91.04436, 16.92175], [-90.69064, 16.70697], [-90.61212, 16.49832], [-90.40499, 16.40524], [-90.44567, 16.07573], [-91.73182, 16.07371], [-92.20983, 15.26077], [-92.0621, 15.07406], [-92.1454, 14.98143], [-92.1423, 14.88647], [-92.18161, 14.84147], [-92.1454, 14.6804], [-92.2261, 14.53423], [-92.37213, 14.39277], [-90.55276, 12.8866], [-90.11344, 13.73679], [-90.10505, 13.85104], [-89.88937, 14.0396], [-89.81807, 14.07073], [-89.76103, 14.02923], [-89.73251, 14.04133], [-89.75569, 14.07073], [-89.70756, 14.1537], [-89.61844, 14.21937], [-89.52397, 14.22628], [-89.50614, 14.26084], [-89.58814, 14.33165], [-89.57441, 14.41637], [-89.39028, 14.44561], [-89.34776, 14.43013], [-89.35189, 14.47553], [-89.23719, 14.58046], [-89.15653, 14.57802], [-89.13132, 14.71582], [-89.23467, 14.85596], [-89.15149, 14.97775], [-89.18048, 14.99967], [-89.15149, 15.07392], [-88.97343, 15.14039], [-88.32467, 15.63665], [-88.31459, 15.66942], [-88.24022, 15.69247], [-88.22552, 15.72294], [-88.20359, 16.03858], [-88.40779, 16.09624], [-88.95358, 15.88698], [-89.02415, 15.9063], [-89.17418, 15.90898], [-89.22683, 15.88619], [-89.15025, 17.04813], [-89.14985, 17.81563]]]]
25286 wikidata: "Q16635",
25288 aliases: ["US-GU"],
25290 groups: ["Q1352230", "Q153732", "057", "009", "UN"],
25291 roadSpeedUnit: "mph",
25292 roadHeightUnit: "ft",
25293 callingCodes: ["1 671"]
25296 type: "MultiPolygon",
25297 coordinates: [[[[146.25931, 13.85876], [143.82485, 13.92273], [144.61642, 12.82462], [146.25931, 13.85876]]]]
25306 nameEn: "Guinea-Bissau",
25307 groups: ["011", "202", "002", "UN"],
25308 callingCodes: ["245"]
25311 type: "MultiPolygon",
25312 coordinates: [[[[-14.31513, 11.60713], [-14.26623, 11.67486], [-14.09799, 11.63649], [-13.7039, 11.70195], [-13.7039, 12.00869], [-13.94589, 12.16869], [-13.92745, 12.24077], [-13.70851, 12.24978], [-13.64168, 12.42764], [-13.65089, 12.49515], [-13.7039, 12.60313], [-13.70523, 12.68013], [-15.17582, 12.6847], [-15.67302, 12.42974], [-16.20591, 12.46157], [-16.38191, 12.36449], [-16.70562, 12.34803], [-17.4623, 11.92379], [-15.96748, 10.162], [-15.07174, 10.89557], [-14.95993, 10.99244], [-14.77786, 11.36323], [-14.66677, 11.51188], [-14.51173, 11.49708], [-14.31513, 11.60713]]]]
25322 groups: ["005", "419", "019", "UN"],
25324 callingCodes: ["592"]
25327 type: "MultiPolygon",
25328 coordinates: [[[[-56.84822, 6.73257], [-59.54058, 8.6862], [-59.98508, 8.53046], [-59.85562, 8.35213], [-59.80661, 8.28906], [-59.83156, 8.23261], [-59.97059, 8.20791], [-60.02407, 8.04557], [-60.38056, 7.8302], [-60.51959, 7.83373], [-60.64793, 7.56877], [-60.71923, 7.55817], [-60.59802, 7.33194], [-60.63367, 7.25061], [-60.54098, 7.14804], [-60.44116, 7.20817], [-60.28074, 7.1162], [-60.39419, 6.94847], [-60.54873, 6.8631], [-61.13632, 6.70922], [-61.20762, 6.58174], [-61.15058, 6.19558], [-61.4041, 5.95304], [-60.73204, 5.20931], [-60.32352, 5.21299], [-60.20944, 5.28754], [-59.98129, 5.07097], [-60.04189, 4.69801], [-60.15953, 4.53456], [-59.78878, 4.45637], [-59.69361, 4.34069], [-59.73353, 4.20399], [-59.51963, 3.91951], [-59.86899, 3.57089], [-59.79769, 3.37162], [-59.99733, 2.92312], [-59.91177, 2.36759], [-59.7264, 2.27497], [-59.74066, 1.87596], [-59.25583, 1.40559], [-58.92072, 1.31293], [-58.84229, 1.17749], [-58.53571, 1.29154], [-58.4858, 1.48399], [-58.33887, 1.58014], [-58.01873, 1.51966], [-57.97336, 1.64566], [-57.77281, 1.73344], [-57.55743, 1.69605], [-57.35073, 1.98327], [-57.23981, 1.95808], [-57.09109, 2.01854], [-57.07092, 1.95304], [-56.7659, 1.89509], [-56.47045, 1.95135], [-56.55439, 2.02003], [-56.70519, 2.02964], [-57.35891, 3.32121], [-58.0307, 3.95513], [-57.8699, 4.89394], [-57.37442, 5.0208], [-57.22536, 5.15605], [-57.31629, 5.33714], [-56.84822, 6.73257]]]]
25337 nameEn: "Hong Kong",
25339 groups: ["030", "142", "UN"],
25341 callingCodes: ["852"]
25344 type: "MultiPolygon",
25345 coordinates: [[[[113.92195, 22.13873], [114.50148, 22.15017], [114.44998, 22.55977], [114.25154, 22.55977], [114.22888, 22.5436], [114.22185, 22.55343], [114.20655, 22.55706], [114.18338, 22.55444], [114.17247, 22.55944], [114.1597, 22.56041], [114.15123, 22.55163], [114.1482, 22.54091], [114.13823, 22.54319], [114.12665, 22.54003], [114.11656, 22.53415], [114.11181, 22.52878], [114.1034, 22.5352], [114.09692, 22.53435], [114.09048, 22.53716], [114.08606, 22.53276], [114.07817, 22.52997], [114.07267, 22.51855], [114.06272, 22.51617], [114.05729, 22.51104], [114.05438, 22.5026], [114.03113, 22.5065], [113.86771, 22.42972], [113.81621, 22.2163], [113.83338, 22.1826], [113.92195, 22.13873]]]]
25353 wikidata: "Q131198",
25354 nameEn: "Heard Island and McDonald Islands",
25356 groups: ["053", "009", "UN"],
25360 type: "MultiPolygon",
25361 coordinates: [[[[71.08716, -53.87687], [75.44182, -53.99822], [72.87012, -51.48322], [71.08716, -53.87687]]]]
25370 nameEn: "Honduras",
25371 groups: ["013", "003", "419", "019", "UN"],
25372 callingCodes: ["504"]
25375 type: "MultiPolygon",
25376 coordinates: [[[[-83.86109, 17.73736], [-88.20359, 16.03858], [-88.22552, 15.72294], [-88.24022, 15.69247], [-88.31459, 15.66942], [-88.32467, 15.63665], [-88.97343, 15.14039], [-89.15149, 15.07392], [-89.18048, 14.99967], [-89.15149, 14.97775], [-89.23467, 14.85596], [-89.13132, 14.71582], [-89.15653, 14.57802], [-89.23719, 14.58046], [-89.35189, 14.47553], [-89.34776, 14.43013], [-89.04187, 14.33644], [-88.94608, 14.20207], [-88.85785, 14.17763], [-88.815, 14.11652], [-88.73182, 14.10919], [-88.70661, 14.04317], [-88.49738, 13.97224], [-88.48982, 13.86458], [-88.25791, 13.91108], [-88.23018, 13.99915], [-88.07641, 13.98447], [-88.00331, 13.86948], [-87.7966, 13.91353], [-87.68821, 13.80829], [-87.73106, 13.75443], [-87.78148, 13.52906], [-87.71657, 13.50577], [-87.72115, 13.46083], [-87.73841, 13.44169], [-87.77354, 13.45767], [-87.83467, 13.44655], [-87.84675, 13.41078], [-87.80177, 13.35689], [-87.73714, 13.32715], [-87.69751, 13.25228], [-87.55124, 13.12523], [-87.37107, 12.98646], [-87.06306, 13.00892], [-87.03785, 12.98682], [-86.93197, 13.05313], [-86.93383, 13.18677], [-86.87066, 13.30641], [-86.71267, 13.30348], [-86.76812, 13.79605], [-86.35219, 13.77157], [-86.14801, 14.04317], [-86.00685, 14.08474], [-86.03458, 13.99181], [-85.75477, 13.8499], [-85.73964, 13.9698], [-85.45762, 14.11304], [-85.32149, 14.2562], [-85.18602, 14.24929], [-85.1575, 14.53934], [-84.90082, 14.80489], [-84.82596, 14.82212], [-84.70119, 14.68078], [-84.48373, 14.63249], [-84.10584, 14.76353], [-83.89551, 14.76697], [-83.62101, 14.89448], [-83.49268, 15.01158], [-83.13724, 15.00002], [-83.04763, 15.03256], [-82.06974, 14.49418], [-81.58685, 18.0025], [-83.86109, 17.73736]]]]
25386 groups: ["EU", "039", "150", "UN"],
25387 callingCodes: ["385"]
25390 type: "MultiPolygon",
25391 coordinates: [[[[17.6444, 42.88641], [17.5392, 42.92787], [17.70879, 42.97223], [17.64268, 43.08595], [17.46986, 43.16559], [17.286, 43.33065], [17.25579, 43.40353], [17.29699, 43.44542], [17.24411, 43.49376], [17.15828, 43.49376], [17.00585, 43.58037], [16.80736, 43.76011], [16.75316, 43.77157], [16.70922, 43.84887], [16.55472, 43.95326], [16.50528, 44.0244], [16.43629, 44.02826], [16.43662, 44.07523], [16.36864, 44.08263], [16.18688, 44.27012], [16.21346, 44.35231], [16.12969, 44.38275], [16.16814, 44.40679], [16.10566, 44.52586], [16.03012, 44.55572], [16.00884, 44.58605], [16.05828, 44.61538], [15.89348, 44.74964], [15.8255, 44.71501], [15.72584, 44.82334], [15.79472, 44.8455], [15.76096, 44.87045], [15.74723, 44.96818], [15.78568, 44.97401], [15.74585, 45.0638], [15.78842, 45.11519], [15.76371, 45.16508], [15.83512, 45.22459], [15.98412, 45.23088], [16.12153, 45.09616], [16.29036, 44.99732], [16.35404, 45.00241], [16.35863, 45.03529], [16.3749, 45.05206], [16.38219, 45.05139], [16.38309, 45.05955], [16.40023, 45.1147], [16.4634, 45.14522], [16.49155, 45.21153], [16.52982, 45.22713], [16.5501, 45.2212], [16.56559, 45.22307], [16.60194, 45.23042], [16.64962, 45.20714], [16.74845, 45.20393], [16.78219, 45.19002], [16.81137, 45.18434], [16.83804, 45.18951], [16.92405, 45.27607], [16.9385, 45.22742], [17.0415, 45.20759], [17.18438, 45.14764], [17.24325, 45.146], [17.25131, 45.14957], [17.26815, 45.18444], [17.32092, 45.16246], [17.33573, 45.14521], [17.41229, 45.13335], [17.4498, 45.16119], [17.45615, 45.12523], [17.47589, 45.12656], [17.51469, 45.10791], [17.59104, 45.10816], [17.66571, 45.13408], [17.84826, 45.04489], [17.87148, 45.04645], [17.93706, 45.08016], [17.97336, 45.12245], [17.97834, 45.13831], [17.99479, 45.14958], [18.01594, 45.15163], [18.03121, 45.12632], [18.1624, 45.07654], [18.24387, 45.13699], [18.32077, 45.1021], [18.41896, 45.11083], [18.47939, 45.05871], [18.65723, 45.07544], [18.78357, 44.97741], [18.80661, 44.93561], [18.76369, 44.93707], [18.76347, 44.90669], [18.8704, 44.85097], [19.01994, 44.85493], [18.98957, 44.90645], [19.02871, 44.92541], [19.06853, 44.89915], [19.15573, 44.95409], [19.05205, 44.97692], [19.1011, 45.01191], [19.07952, 45.14668], [19.14063, 45.12972], [19.19144, 45.17863], [19.43589, 45.17137], [19.41941, 45.23475], [19.28208, 45.23813], [19.10774, 45.29547], [18.97446, 45.37528], [18.99918, 45.49333], [19.08364, 45.48804], [19.07471, 45.53086], [18.94562, 45.53712], [18.88776, 45.57253], [18.96691, 45.66731], [18.90305, 45.71863], [18.85783, 45.85493], [18.81394, 45.91329], [18.80211, 45.87995], [18.6792, 45.92057], [18.57483, 45.80772], [18.44368, 45.73972], [18.12439, 45.78905], [18.08869, 45.76511], [17.99805, 45.79671], [17.87377, 45.78522], [17.66545, 45.84207], [17.56821, 45.93728], [17.35672, 45.95209], [17.14592, 46.16697], [16.8903, 46.28122], [16.8541, 46.36255], [16.7154, 46.39523], [16.6639, 46.45203], [16.59527, 46.47524], [16.52604, 46.47831], [16.5007, 46.49644], [16.44036, 46.5171], [16.38771, 46.53608], [16.37193, 46.55008], [16.29793, 46.5121], [16.26733, 46.51505], [16.26759, 46.50566], [16.23961, 46.49653], [16.25124, 46.48067], [16.27398, 46.42875], [16.27329, 46.41467], [16.30162, 46.40437], [16.30233, 46.37837], [16.18824, 46.38282], [16.14859, 46.40547], [16.05281, 46.39141], [16.05065, 46.3833], [16.07314, 46.36458], [16.07616, 46.3463], [15.97965, 46.30652], [15.79284, 46.25811], [15.78817, 46.21719], [15.75479, 46.20336], [15.75436, 46.21969], [15.67395, 46.22478], [15.6434, 46.21396], [15.64904, 46.19229], [15.59909, 46.14761], [15.6083, 46.11992], [15.62317, 46.09103], [15.72977, 46.04682], [15.71246, 46.01196], [15.70327, 46.00015], [15.70636, 45.92116], [15.67967, 45.90455], [15.68383, 45.88867], [15.68232, 45.86819], [15.70411, 45.8465], [15.66662, 45.84085], [15.64185, 45.82915], [15.57952, 45.84953], [15.52234, 45.82195], [15.47325, 45.8253], [15.47531, 45.79802], [15.40836, 45.79491], [15.25423, 45.72275], [15.30872, 45.69014], [15.34919, 45.71623], [15.4057, 45.64727], [15.38952, 45.63682], [15.34214, 45.64702], [15.34695, 45.63382], [15.31027, 45.6303], [15.27747, 45.60504], [15.29837, 45.5841], [15.30249, 45.53224], [15.38188, 45.48752], [15.33051, 45.45258], [15.27758, 45.46678], [15.16862, 45.42309], [15.05187, 45.49079], [15.02385, 45.48533], [14.92266, 45.52788], [14.90554, 45.47769], [14.81992, 45.45913], [14.80124, 45.49515], [14.71718, 45.53442], [14.68605, 45.53006], [14.69694, 45.57366], [14.59576, 45.62812], [14.60977, 45.66403], [14.57397, 45.67165], [14.53816, 45.6205], [14.5008, 45.60852], [14.49769, 45.54424], [14.36693, 45.48642], [14.32487, 45.47142], [14.27681, 45.4902], [14.26611, 45.48239], [14.24239, 45.50607], [14.22371, 45.50388], [14.20348, 45.46896], [14.07116, 45.48752], [14.00578, 45.52352], [13.96063, 45.50825], [13.99488, 45.47551], [13.97309, 45.45258], [13.90771, 45.45149], [13.88124, 45.42637], [13.81742, 45.43729], [13.7785, 45.46787], [13.67398, 45.4436], [13.62902, 45.45898], [13.56979, 45.4895], [13.45644, 45.59464], [13.05142, 45.33128], [13.12821, 44.48877], [16.15283, 42.18525], [18.45131, 42.21682], [18.54128, 42.39171], [18.52152, 42.42302], [18.43588, 42.48556], [18.44307, 42.51077], [18.43735, 42.55921], [18.36197, 42.61423], [18.24318, 42.6112], [17.88201, 42.83668], [17.80854, 42.9182], [17.7948, 42.89556], [17.68151, 42.92725], [17.6444, 42.88641]]]]
25402 groups: ["029", "003", "419", "019", "UN"],
25403 callingCodes: ["509"]
25406 type: "MultiPolygon",
25407 coordinates: [[[[-71.71885, 18.78423], [-71.72624, 18.87802], [-71.77766, 18.95007], [-71.88102, 18.95007], [-71.74088, 19.0437], [-71.71088, 19.08353], [-71.69938, 19.10916], [-71.65337, 19.11759], [-71.62642, 19.21212], [-71.73229, 19.26686], [-71.77766, 19.33823], [-71.69448, 19.37866], [-71.6802, 19.45008], [-71.71268, 19.53374], [-71.71449, 19.55364], [-71.7429, 19.58445], [-71.75865, 19.70231], [-71.77419, 19.73128], [-72.38946, 20.27111], [-73.37289, 20.43199], [-74.7289, 18.71009], [-74.76465, 18.06252], [-72.29523, 17.48026], [-71.75671, 18.03456], [-71.73783, 18.07177], [-71.74994, 18.11115], [-71.75465, 18.14405], [-71.78271, 18.18302], [-71.69952, 18.34101], [-71.90875, 18.45821], [-71.88102, 18.50125], [-72.00201, 18.62312], [-71.95412, 18.64939], [-71.82556, 18.62551], [-71.71885, 18.78423]]]]
25417 groups: ["EU", "151", "150", "UN"],
25418 callingCodes: ["36"]
25421 type: "MultiPolygon",
25422 coordinates: [[[[21.72525, 48.34628], [21.67134, 48.3989], [21.6068, 48.50365], [21.44063, 48.58456], [21.11516, 48.49546], [20.83248, 48.5824], [20.5215, 48.53336], [20.29943, 48.26104], [20.24312, 48.2784], [19.92452, 48.1283], [19.63338, 48.25006], [19.52489, 48.19791], [19.47957, 48.09437], [19.28182, 48.08336], [19.23924, 48.0595], [19.01952, 48.07052], [18.82176, 48.04206], [18.76134, 47.97499], [18.76821, 47.87469], [18.8506, 47.82308], [18.74074, 47.8157], [18.66521, 47.76772], [18.56496, 47.76588], [18.29305, 47.73541], [18.02938, 47.75665], [17.71215, 47.7548], [17.23699, 48.02094], [17.16001, 48.00636], [17.09786, 47.97336], [17.11022, 47.92461], [17.08275, 47.87719], [17.00997, 47.86245], [17.07039, 47.81129], [17.05048, 47.79377], [17.08893, 47.70928], [16.87538, 47.68895], [16.86509, 47.72268], [16.82938, 47.68432], [16.7511, 47.67878], [16.72089, 47.73469], [16.65679, 47.74197], [16.61183, 47.76171], [16.54779, 47.75074], [16.53514, 47.73837], [16.55129, 47.72268], [16.4222, 47.66537], [16.58699, 47.61772], [16.64193, 47.63114], [16.71059, 47.52692], [16.64821, 47.50155], [16.6718, 47.46139], [16.57152, 47.40868], [16.52414, 47.41007], [16.49908, 47.39416], [16.45104, 47.41181], [16.47782, 47.25918], [16.44142, 47.25079], [16.43663, 47.21127], [16.41739, 47.20649], [16.42801, 47.18422], [16.4523, 47.18812], [16.46442, 47.16845], [16.44932, 47.14418], [16.52863, 47.13974], [16.46134, 47.09395], [16.52176, 47.05747], [16.43936, 47.03548], [16.51369, 47.00084], [16.28202, 47.00159], [16.27594, 46.9643], [16.22403, 46.939], [16.19904, 46.94134], [16.10983, 46.867], [16.14365, 46.8547], [16.15711, 46.85434], [16.21892, 46.86961], [16.2365, 46.87775], [16.2941, 46.87137], [16.34547, 46.83836], [16.3408, 46.80641], [16.31303, 46.79838], [16.30966, 46.7787], [16.37816, 46.69975], [16.42641, 46.69228], [16.41863, 46.66238], [16.38594, 46.6549], [16.39217, 46.63673], [16.50139, 46.56684], [16.52885, 46.53303], [16.52604, 46.5051], [16.59527, 46.47524], [16.6639, 46.45203], [16.7154, 46.39523], [16.8541, 46.36255], [16.8903, 46.28122], [17.14592, 46.16697], [17.35672, 45.95209], [17.56821, 45.93728], [17.66545, 45.84207], [17.87377, 45.78522], [17.99805, 45.79671], [18.08869, 45.76511], [18.12439, 45.78905], [18.44368, 45.73972], [18.57483, 45.80772], [18.6792, 45.92057], [18.80211, 45.87995], [18.81394, 45.91329], [18.99712, 45.93537], [19.01284, 45.96529], [19.0791, 45.96458], [19.10388, 46.04015], [19.14543, 45.9998], [19.28826, 45.99694], [19.52473, 46.1171], [19.56113, 46.16824], [19.66007, 46.19005], [19.81491, 46.1313], [19.93508, 46.17553], [20.01816, 46.17696], [20.03533, 46.14509], [20.09713, 46.17315], [20.26068, 46.12332], [20.28324, 46.1438], [20.35573, 46.16629], [20.45377, 46.14405], [20.49718, 46.18721], [20.63863, 46.12728], [20.76085, 46.21002], [20.74574, 46.25467], [20.86797, 46.28884], [21.06572, 46.24897], [21.16872, 46.30118], [21.28061, 46.44941], [21.26929, 46.4993], [21.33214, 46.63035], [21.43926, 46.65109], [21.5151, 46.72147], [21.48935, 46.7577], [21.52028, 46.84118], [21.59307, 46.86935], [21.59581, 46.91628], [21.68645, 46.99595], [21.648, 47.03902], [21.78395, 47.11104], [21.94463, 47.38046], [22.01055, 47.37767], [22.03389, 47.42508], [22.00917, 47.50492], [22.31816, 47.76126], [22.41979, 47.7391], [22.46559, 47.76583], [22.67247, 47.7871], [22.76617, 47.8417], [22.77991, 47.87211], [22.89849, 47.95851], [22.84276, 47.98602], [22.87847, 48.04665], [22.81804, 48.11363], [22.73427, 48.12005], [22.66835, 48.09162], [22.58733, 48.10813], [22.59007, 48.15121], [22.49806, 48.25189], [22.38133, 48.23726], [22.2083, 48.42534], [22.14689, 48.4005], [21.83339, 48.36242], [21.8279, 48.33321], [21.72525, 48.34628]]]]
25429 nameEn: "Canary Islands",
25431 groups: ["Q3320166", "Q105472", "EU", "039", "150", "UN"],
25432 isoStatus: "excRes",
25433 callingCodes: ["34"]
25436 type: "MultiPolygon",
25437 coordinates: [[[[-12.00985, 30.24121], [-25.3475, 27.87574], [-14.43883, 27.02969], [-12.00985, 30.24121]]]]
25446 nameEn: "Indonesia",
25457 nameEn: "Republic of Ireland",
25458 groups: ["EU", "Q22890", "154", "150", "UN"],
25460 callingCodes: ["353"]
25463 type: "MultiPolygon",
25464 coordinates: [[[[-6.26218, 54.09785], [-6.29003, 54.11278], [-6.32694, 54.09337], [-6.36279, 54.11248], [-6.36605, 54.07234], [-6.47849, 54.06947], [-6.62842, 54.03503], [-6.66264, 54.0666], [-6.6382, 54.17071], [-6.70175, 54.20218], [-6.74575, 54.18788], [-6.81583, 54.22791], [-6.85179, 54.29176], [-6.87775, 54.34682], [-7.02034, 54.4212], [-7.19145, 54.31296], [-7.14908, 54.22732], [-7.25012, 54.20063], [-7.26316, 54.13863], [-7.29493, 54.12013], [-7.29687, 54.1354], [-7.28017, 54.16714], [-7.29157, 54.17191], [-7.34005, 54.14698], [-7.30553, 54.11869], [-7.32834, 54.11475], [-7.44567, 54.1539], [-7.4799, 54.12239], [-7.55812, 54.12239], [-7.69501, 54.20731], [-7.81397, 54.20159], [-7.8596, 54.21779], [-7.87101, 54.29299], [-8.04555, 54.36292], [-8.179, 54.46763], [-8.04538, 54.48941], [-7.99812, 54.54427], [-7.8596, 54.53671], [-7.70315, 54.62077], [-7.93293, 54.66603], [-7.83352, 54.73854], [-7.75041, 54.7103], [-7.64449, 54.75265], [-7.54671, 54.74606], [-7.54508, 54.79401], [-7.47626, 54.83084], [-7.4473, 54.87003], [-7.44404, 54.9403], [-7.40004, 54.94498], [-7.4033, 55.00391], [-7.34464, 55.04688], [-7.2471, 55.06933], [-6.34755, 55.49206], [-7.75229, 55.93854], [-22.01468, 48.19557], [-6.03913, 51.13217], [-5.37267, 53.63269], [-6.26218, 54.09785]]]]
25474 groups: ["145", "142", "UN"],
25475 callingCodes: ["972"]
25478 type: "MultiPolygon",
25479 coordinates: [[[[34.052, 31.46619], [34.29262, 31.70393], [34.48681, 31.59711], [34.56797, 31.54197], [34.48892, 31.48365], [34.40077, 31.40926], [34.36505, 31.36404], [34.37381, 31.30598], [34.36523, 31.28963], [34.29417, 31.24194], [34.26742, 31.21998], [34.92298, 29.45305], [34.97718, 29.54294], [34.98207, 29.58147], [35.02147, 29.66343], [35.14108, 30.07374], [35.19183, 30.34636], [35.16218, 30.43535], [35.19595, 30.50297], [35.21379, 30.60401], [35.29311, 30.71365], [35.33456, 30.81224], [35.33984, 30.8802], [35.41371, 30.95565], [35.43658, 31.12444], [35.40316, 31.25535], [35.47672, 31.49578], [35.39675, 31.49572], [35.22921, 31.37445], [35.13033, 31.3551], [35.02459, 31.35979], [34.92571, 31.34337], [34.88932, 31.37093], [34.87833, 31.39321], [34.89756, 31.43891], [34.93258, 31.47816], [34.94356, 31.50743], [34.9415, 31.55601], [34.95249, 31.59813], [35.00879, 31.65426], [35.08226, 31.69107], [35.10782, 31.71594], [35.11895, 31.71454], [35.12933, 31.7325], [35.13931, 31.73012], [35.15119, 31.73634], [35.15474, 31.73352], [35.16478, 31.73242], [35.18023, 31.72067], [35.20538, 31.72388], [35.21937, 31.71578], [35.22392, 31.71899], [35.23972, 31.70896], [35.24315, 31.71244], [35.2438, 31.7201], [35.24981, 31.72543], [35.25182, 31.73945], [35.26319, 31.74846], [35.25225, 31.7678], [35.26058, 31.79064], [35.25573, 31.81362], [35.26404, 31.82567], [35.251, 31.83085], [35.25753, 31.8387], [35.24816, 31.8458], [35.2304, 31.84222], [35.2249, 31.85433], [35.22817, 31.8638], [35.22567, 31.86745], [35.22294, 31.87889], [35.22014, 31.88264], [35.2136, 31.88241], [35.21276, 31.88153], [35.21016, 31.88237], [35.20945, 31.8815], [35.20791, 31.8821], [35.20673, 31.88151], [35.20381, 31.86716], [35.21128, 31.863], [35.216, 31.83894], [35.21469, 31.81835], [35.19461, 31.82687], [35.18169, 31.82542], [35.18603, 31.80901], [35.14174, 31.81325], [35.07677, 31.85627], [35.05617, 31.85685], [35.01978, 31.82944], [34.9724, 31.83352], [34.99712, 31.85569], [35.03489, 31.85919], [35.03978, 31.89276], [35.03489, 31.92448], [35.00124, 31.93264], [34.98682, 31.96935], [35.00261, 32.027], [34.9863, 32.09551], [34.99437, 32.10962], [34.98507, 32.12606], [34.99039, 32.14626], [34.96009, 32.17503], [34.95703, 32.19522], [34.98885, 32.20758], [35.01841, 32.23981], [35.02939, 32.2671], [35.01119, 32.28684], [35.01772, 32.33863], [35.04243, 32.35008], [35.05142, 32.3667], [35.0421, 32.38242], [35.05311, 32.4024], [35.05423, 32.41754], [35.07059, 32.4585], [35.08564, 32.46948], [35.09236, 32.47614], [35.10024, 32.47856], [35.10882, 32.4757], [35.15937, 32.50466], [35.2244, 32.55289], [35.25049, 32.52453], [35.29306, 32.50947], [35.30685, 32.51024], [35.35212, 32.52047], [35.40224, 32.50136], [35.42034, 32.46009], [35.41598, 32.45593], [35.41048, 32.43706], [35.42078, 32.41562], [35.55807, 32.38674], [35.55494, 32.42687], [35.57485, 32.48669], [35.56614, 32.64393], [35.59813, 32.65159], [35.61669, 32.67999], [35.66527, 32.681], [35.68467, 32.70715], [35.75983, 32.74803], [35.78745, 32.77938], [35.83758, 32.82817], [35.84021, 32.8725], [35.87012, 32.91976], [35.89298, 32.9456], [35.87188, 32.98028], [35.84802, 33.1031], [35.81911, 33.11077], [35.81911, 33.1336], [35.84285, 33.16673], [35.83846, 33.19397], [35.81647, 33.2028], [35.81295, 33.24841], [35.77513, 33.27342], [35.813, 33.3172], [35.77477, 33.33609], [35.62019, 33.27278], [35.62283, 33.24226], [35.58502, 33.26653], [35.58326, 33.28381], [35.56523, 33.28969], [35.55555, 33.25844], [35.54544, 33.25513], [35.54808, 33.236], [35.5362, 33.23196], [35.54228, 33.19865], [35.52573, 33.11921], [35.50335, 33.114], [35.50272, 33.09056], [35.448, 33.09264], [35.43059, 33.06659], [35.35223, 33.05617], [35.31429, 33.10515], [35.1924, 33.08743], [35.10645, 33.09318], [34.78515, 33.20368], [33.62659, 31.82938], [34.052, 31.46619]]]]
25488 nameEn: "Isle of Man",
25490 groups: ["Q185086", "154", "150", "UN"],
25492 roadSpeedUnit: "mph",
25493 roadHeightUnit: "ft",
25494 callingCodes: ["44 01624", "44 07624", "44 07524", "44 07924"]
25497 type: "MultiPolygon",
25498 coordinates: [[[[-3.98763, 54.07351], [-4.1819, 54.57861], [-5.6384, 53.81157], [-3.98763, 54.07351]]]]
25516 wikidata: "Q43448",
25517 nameEn: "British Indian Ocean Territory",
25529 groups: ["145", "142", "UN"],
25530 callingCodes: ["964"]
25533 type: "MultiPolygon",
25534 coordinates: [[[[42.78887, 37.38615], [42.56725, 37.14878], [42.35724, 37.10998], [42.36697, 37.0627], [41.81736, 36.58782], [41.40058, 36.52502], [41.28864, 36.35368], [41.2564, 36.06012], [41.37027, 35.84095], [41.38184, 35.62502], [41.26569, 35.42708], [41.21654, 35.1508], [41.2345, 34.80049], [41.12388, 34.65742], [40.97676, 34.39788], [40.64314, 34.31604], [38.79171, 33.37328], [39.08202, 32.50304], [38.98762, 32.47694], [39.04251, 32.30203], [39.26157, 32.35555], [39.29903, 32.23259], [40.01521, 32.05667], [42.97601, 30.72204], [42.97796, 30.48295], [44.72255, 29.19736], [46.42415, 29.05947], [46.5527, 29.10283], [46.89695, 29.50584], [47.15166, 30.01044], [47.37192, 30.10421], [47.7095, 30.10453], [48.01114, 29.98906], [48.06782, 30.02906], [48.17332, 30.02448], [48.40479, 29.85763], [48.59531, 29.66815], [48.83867, 29.78572], [48.61441, 29.93675], [48.51011, 29.96238], [48.44785, 30.00148], [48.4494, 30.04456], [48.43384, 30.08233], [48.38869, 30.11062], [48.38714, 30.13485], [48.41671, 30.17254], [48.41117, 30.19846], [48.26393, 30.3408], [48.24385, 30.33846], [48.21279, 30.31644], [48.19425, 30.32796], [48.18321, 30.39703], [48.14585, 30.44133], [48.02443, 30.4789], [48.03221, 30.9967], [47.68219, 31.00004], [47.6804, 31.39086], [47.86337, 31.78422], [47.64771, 32.07666], [47.52474, 32.15972], [47.57144, 32.20583], [47.37529, 32.47808], [47.17218, 32.45393], [46.46788, 32.91992], [46.32298, 32.9731], [46.17198, 32.95612], [46.09103, 32.98354], [46.15175, 33.07229], [46.03966, 33.09577], [46.05367, 33.13097], [46.11905, 33.11924], [46.20623, 33.20395], [45.99919, 33.5082], [45.86687, 33.49263], [45.96183, 33.55751], [45.89801, 33.63661], [45.77814, 33.60938], [45.50261, 33.94968], [45.42789, 33.9458], [45.41077, 33.97421], [45.47264, 34.03099], [45.56176, 34.15088], [45.58667, 34.30147], [45.53552, 34.35148], [45.49171, 34.3439], [45.46697, 34.38221], [45.43879, 34.45949], [45.51883, 34.47692], [45.53219, 34.60441], [45.59074, 34.55558], [45.60224, 34.55057], [45.73923, 34.54416], [45.70031, 34.69277], [45.65672, 34.7222], [45.68284, 34.76624], [45.70031, 34.82322], [45.73641, 34.83975], [45.79682, 34.85133], [45.78904, 34.91135], [45.86532, 34.89858], [45.89477, 34.95805], [45.87864, 35.03441], [45.92173, 35.0465], [45.92203, 35.09538], [45.93108, 35.08148], [45.94756, 35.09188], [46.06508, 35.03699], [46.07747, 35.0838], [46.11763, 35.07551], [46.19116, 35.11097], [46.15642, 35.1268], [46.16229, 35.16984], [46.19738, 35.18536], [46.18457, 35.22561], [46.11367, 35.23729], [46.15474, 35.2883], [46.13152, 35.32548], [46.05358, 35.38568], [45.98453, 35.49848], [46.01518, 35.52012], [45.97584, 35.58132], [46.03028, 35.57416], [46.01307, 35.59756], [46.0165, 35.61501], [45.99452, 35.63574], [46.0117, 35.65059], [46.01631, 35.69139], [46.23736, 35.71414], [46.34166, 35.78363], [46.32921, 35.82655], [46.17198, 35.8013], [46.08325, 35.8581], [45.94711, 35.82218], [45.89784, 35.83708], [45.81442, 35.82107], [45.76145, 35.79898], [45.6645, 35.92872], [45.60018, 35.96069], [45.55245, 35.99943], [45.46594, 36.00042], [45.38275, 35.97156], [45.33916, 35.99424], [45.37652, 36.06222], [45.37312, 36.09917], [45.32235, 36.17383], [45.30038, 36.27769], [45.26261, 36.3001], [45.27394, 36.35846], [45.23953, 36.43257], [45.11811, 36.40751], [45.00759, 36.5402], [45.06985, 36.62645], [45.06985, 36.6814], [45.01537, 36.75128], [44.84725, 36.77622], [44.83479, 36.81362], [44.90173, 36.86096], [44.91199, 36.91468], [44.89862, 37.01897], [44.81611, 37.04383], [44.75229, 37.11958], [44.78319, 37.1431], [44.76698, 37.16162], [44.63179, 37.19229], [44.42631, 37.05825], [44.38117, 37.05825], [44.35315, 37.04955], [44.35937, 37.02843], [44.30645, 36.97373], [44.25975, 36.98119], [44.18503, 37.09551], [44.22239, 37.15756], [44.27998, 37.16501], [44.2613, 37.25055], [44.13521, 37.32486], [44.02002, 37.33229], [43.90949, 37.22453], [43.84878, 37.22205], [43.82699, 37.19477], [43.8052, 37.22825], [43.7009, 37.23692], [43.63085, 37.21957], [43.56702, 37.25675], [43.50787, 37.24436], [43.33508, 37.33105], [43.30083, 37.30629], [43.11403, 37.37436], [42.93705, 37.32015], [42.78887, 37.38615]]]]
25544 groups: ["034", "142", "UN"],
25545 callingCodes: ["98"]
25548 type: "MultiPolygon",
25549 coordinates: [[[[44.96746, 39.42998], [44.88916, 39.59653], [44.81043, 39.62677], [44.71806, 39.71124], [44.65422, 39.72163], [44.6137, 39.78393], [44.47298, 39.68788], [44.48111, 39.61579], [44.41849, 39.56659], [44.42832, 39.4131], [44.37921, 39.4131], [44.29818, 39.378], [44.22452, 39.4169], [44.03667, 39.39223], [44.1043, 39.19842], [44.20946, 39.13975], [44.18863, 38.93881], [44.30322, 38.81581], [44.26155, 38.71427], [44.28065, 38.6465], [44.32058, 38.62752], [44.3207, 38.49799], [44.3119, 38.37887], [44.38309, 38.36117], [44.44386, 38.38295], [44.50115, 38.33939], [44.42476, 38.25763], [44.22509, 37.88859], [44.3883, 37.85433], [44.45948, 37.77065], [44.55498, 37.783], [44.62096, 37.71985], [44.56887, 37.6429], [44.61401, 37.60165], [44.58449, 37.45018], [44.81021, 37.2915], [44.75986, 37.21549], [44.7868, 37.16644], [44.78319, 37.1431], [44.75229, 37.11958], [44.81611, 37.04383], [44.89862, 37.01897], [44.91199, 36.91468], [44.90173, 36.86096], [44.83479, 36.81362], [44.84725, 36.77622], [45.01537, 36.75128], [45.06985, 36.6814], [45.06985, 36.62645], [45.00759, 36.5402], [45.11811, 36.40751], [45.23953, 36.43257], [45.27394, 36.35846], [45.26261, 36.3001], [45.30038, 36.27769], [45.32235, 36.17383], [45.37312, 36.09917], [45.37652, 36.06222], [45.33916, 35.99424], [45.38275, 35.97156], [45.46594, 36.00042], [45.55245, 35.99943], [45.60018, 35.96069], [45.6645, 35.92872], [45.76145, 35.79898], [45.81442, 35.82107], [45.89784, 35.83708], [45.94711, 35.82218], [46.08325, 35.8581], [46.17198, 35.8013], [46.32921, 35.82655], [46.34166, 35.78363], [46.23736, 35.71414], [46.01631, 35.69139], [46.0117, 35.65059], [45.99452, 35.63574], [46.0165, 35.61501], [46.01307, 35.59756], [46.03028, 35.57416], [45.97584, 35.58132], [46.01518, 35.52012], [45.98453, 35.49848], [46.05358, 35.38568], [46.13152, 35.32548], [46.15474, 35.2883], [46.11367, 35.23729], [46.18457, 35.22561], [46.19738, 35.18536], [46.16229, 35.16984], [46.15642, 35.1268], [46.19116, 35.11097], [46.11763, 35.07551], [46.07747, 35.0838], [46.06508, 35.03699], [45.94756, 35.09188], [45.93108, 35.08148], [45.92203, 35.09538], [45.92173, 35.0465], [45.87864, 35.03441], [45.89477, 34.95805], [45.86532, 34.89858], [45.78904, 34.91135], [45.79682, 34.85133], [45.73641, 34.83975], [45.70031, 34.82322], [45.68284, 34.76624], [45.65672, 34.7222], [45.70031, 34.69277], [45.73923, 34.54416], [45.60224, 34.55057], [45.59074, 34.55558], [45.53219, 34.60441], [45.51883, 34.47692], [45.43879, 34.45949], [45.46697, 34.38221], [45.49171, 34.3439], [45.53552, 34.35148], [45.58667, 34.30147], [45.56176, 34.15088], [45.47264, 34.03099], [45.41077, 33.97421], [45.42789, 33.9458], [45.50261, 33.94968], [45.77814, 33.60938], [45.89801, 33.63661], [45.96183, 33.55751], [45.86687, 33.49263], [45.99919, 33.5082], [46.20623, 33.20395], [46.11905, 33.11924], [46.05367, 33.13097], [46.03966, 33.09577], [46.15175, 33.07229], [46.09103, 32.98354], [46.17198, 32.95612], [46.32298, 32.9731], [46.46788, 32.91992], [47.17218, 32.45393], [47.37529, 32.47808], [47.57144, 32.20583], [47.52474, 32.15972], [47.64771, 32.07666], [47.86337, 31.78422], [47.6804, 31.39086], [47.68219, 31.00004], [48.03221, 30.9967], [48.02443, 30.4789], [48.14585, 30.44133], [48.18321, 30.39703], [48.19425, 30.32796], [48.21279, 30.31644], [48.24385, 30.33846], [48.26393, 30.3408], [48.41117, 30.19846], [48.41671, 30.17254], [48.38714, 30.13485], [48.38869, 30.11062], [48.43384, 30.08233], [48.4494, 30.04456], [48.44785, 30.00148], [48.51011, 29.96238], [48.61441, 29.93675], [48.83867, 29.78572], [49.98877, 27.87827], [50.37726, 27.89227], [54.39838, 25.68383], [55.14145, 25.62624], [55.81777, 26.18798], [56.2644, 26.58649], [56.68954, 26.76645], [56.79239, 26.41236], [56.82555, 25.7713], [56.86325, 25.03856], [61.46682, 24.57869], [61.6433, 25.27541], [61.683, 25.66638], [61.83968, 25.7538], [61.83831, 26.07249], [61.89391, 26.26251], [62.05117, 26.31647], [62.21304, 26.26601], [62.31484, 26.528], [62.77352, 26.64099], [63.1889, 26.65072], [63.18688, 26.83844], [63.25005, 26.84212], [63.25005, 27.08692], [63.32283, 27.14437], [63.19649, 27.25674], [62.80604, 27.22412], [62.79684, 27.34381], [62.84905, 27.47627], [62.7638, 28.02992], [62.79412, 28.28108], [62.59499, 28.24842], [62.40259, 28.42703], [61.93581, 28.55284], [61.65978, 28.77937], [61.53765, 29.00507], [61.31508, 29.38903], [60.87231, 29.86514], [61.80829, 30.84224], [61.78268, 30.92724], [61.8335, 30.97669], [61.83257, 31.0452], [61.80957, 31.12576], [61.80569, 31.16167], [61.70929, 31.37391], [60.84541, 31.49561], [60.86191, 32.22565], [60.56485, 33.12944], [60.88908, 33.50219], [60.91133, 33.55596], [60.69573, 33.56054], [60.57762, 33.59772], [60.5485, 33.73422], [60.5838, 33.80793], [60.50209, 34.13992], [60.66502, 34.31539], [60.91321, 34.30411], [60.72316, 34.52857], [60.99922, 34.63064], [61.00197, 34.70631], [61.06926, 34.82139], [61.12831, 35.09938], [61.0991, 35.27845], [61.18187, 35.30249], [61.27371, 35.61482], [61.22719, 35.67038], [61.26152, 35.80749], [61.22444, 35.92879], [61.12007, 35.95992], [61.22719, 36.12759], [61.1393, 36.38782], [61.18187, 36.55348], [61.14516, 36.64644], [60.34767, 36.63214], [60.00768, 37.04102], [59.74678, 37.12499], [59.55178, 37.13594], [59.39385, 37.34257], [59.39797, 37.47892], [59.33507, 37.53146], [59.22905, 37.51161], [58.9338, 37.67374], [58.6921, 37.64548], [58.5479, 37.70526], [58.47786, 37.6433], [58.39959, 37.63134], [58.22999, 37.6856], [58.21399, 37.77281], [57.79534, 37.89299], [57.35042, 37.98546], [57.37236, 38.09321], [57.21169, 38.28965], [57.03453, 38.18717], [56.73928, 38.27887], [56.62255, 38.24005], [56.43303, 38.26054], [56.32454, 38.18502], [56.33278, 38.08132], [55.97847, 38.08024], [55.76561, 38.12238], [55.44152, 38.08564], [55.13412, 37.94705], [54.851, 37.75739], [54.77684, 37.62264], [54.81804, 37.61285], [54.77822, 37.51597], [54.67247, 37.43532], [54.58664, 37.45809], [54.36211, 37.34912], [54.24565, 37.32047], [53.89734, 37.3464], [48.88288, 38.43975], [48.84969, 38.45015], [48.81072, 38.44853], [48.78979, 38.45026], [48.70001, 38.40564], [48.62217, 38.40198], [48.58793, 38.45076], [48.45084, 38.61013], [48.3146, 38.59958], [48.24773, 38.71883], [48.02581, 38.82705], [48.01409, 38.90333], [48.07734, 38.91616], [48.08627, 38.94434], [48.28437, 38.97186], [48.33884, 39.03022], [48.31239, 39.09278], [48.15361, 39.19419], [48.12404, 39.25208], [48.15984, 39.30028], [48.37385, 39.37584], [48.34264, 39.42935], [47.98977, 39.70999], [47.84774, 39.66285], [47.50099, 39.49615], [47.38978, 39.45999], [47.31301, 39.37492], [47.05927, 39.24846], [47.05771, 39.20143], [46.95341, 39.13505], [46.92539, 39.16644], [46.83822, 39.13143], [46.75752, 39.03231], [46.53497, 38.86548], [46.34059, 38.92076], [46.20601, 38.85262], [46.14785, 38.84206], [46.06766, 38.87861], [46.00228, 38.87376], [45.94624, 38.89072], [45.90266, 38.87739], [45.83883, 38.90768], [45.65172, 38.95199], [45.6155, 38.94304], [45.6131, 38.964], [45.44966, 38.99243], [45.44811, 39.04927], [45.40452, 39.07224], [45.40148, 39.09007], [45.30489, 39.18333], [45.16168, 39.21952], [45.08751, 39.35052], [45.05932, 39.36435], [44.96746, 39.42998]]]]
25559 groups: ["154", "150", "UN"],
25560 callingCodes: ["354"]
25563 type: "MultiPolygon",
25564 coordinates: [[[[-33.15676, 62.62995], [-8.25539, 63.0423], [-15.70914, 69.67442], [-33.15676, 62.62995]]]]
25574 groups: ["EU", "039", "150", "UN"],
25575 callingCodes: ["39"]
25578 type: "MultiPolygon",
25579 coordinates: [[[[8.95861, 45.96485], [8.97604, 45.96151], [8.97741, 45.98317], [8.96668, 45.98436], [8.95861, 45.96485]]], [[[7.63035, 43.57419], [9.56115, 43.20816], [10.09675, 41.44089], [7.60802, 41.05927], [7.89009, 38.19924], [11.2718, 37.6713], [12.13667, 34.20326], [14.02721, 36.53141], [17.67657, 35.68918], [18.83516, 40.36999], [16.15283, 42.18525], [13.12821, 44.48877], [13.05142, 45.33128], [13.45644, 45.59464], [13.6076, 45.64761], [13.7198, 45.59352], [13.74587, 45.59811], [13.78445, 45.5825], [13.84106, 45.58185], [13.86771, 45.59898], [13.8695, 45.60835], [13.9191, 45.6322], [13.87933, 45.65207], [13.83422, 45.68703], [13.83332, 45.70855], [13.8235, 45.7176], [13.66986, 45.79955], [13.59784, 45.8072], [13.58858, 45.83503], [13.57563, 45.8425], [13.58644, 45.88173], [13.59565, 45.89446], [13.60857, 45.89907], [13.61931, 45.91782], [13.63815, 45.93607], [13.6329, 45.94894], [13.64307, 45.98326], [13.63458, 45.98947], [13.62074, 45.98388], [13.58903, 45.99009], [13.56759, 45.96991], [13.52963, 45.96588], [13.50104, 45.98078], [13.47474, 46.00546], [13.49702, 46.01832], [13.50998, 46.04498], [13.49568, 46.04839], [13.50104, 46.05986], [13.57072, 46.09022], [13.64053, 46.13587], [13.66472, 46.17392], [13.64451, 46.18966], [13.56682, 46.18703], [13.56114, 46.2054], [13.47587, 46.22725], [13.42218, 46.20758], [13.37671, 46.29668], [13.44808, 46.33507], [13.43418, 46.35992], [13.47019, 46.3621], [13.5763, 46.40915], [13.5763, 46.42613], [13.59777, 46.44137], [13.68684, 46.43881], [13.7148, 46.5222], [13.64088, 46.53438], [13.27627, 46.56059], [12.94445, 46.60401], [12.59992, 46.6595], [12.38708, 46.71529], [12.27591, 46.88651], [12.2006, 46.88854], [12.11675, 47.01241], [12.21781, 47.03996], [12.19254, 47.09331], [11.74789, 46.98484], [11.50739, 47.00644], [11.33355, 46.99862], [11.10618, 46.92966], [11.00764, 46.76896], [10.72974, 46.78972], [10.75753, 46.82258], [10.66405, 46.87614], [10.54783, 46.84505], [10.47197, 46.85698], [10.38659, 46.67847], [10.40475, 46.63671], [10.44686, 46.64162], [10.49375, 46.62049], [10.46136, 46.53164], [10.25309, 46.57432], [10.23674, 46.63484], [10.10307, 46.61003], [10.03715, 46.44479], [10.165, 46.41051], [10.10506, 46.3372], [10.17862, 46.25626], [10.14439, 46.22992], [10.07055, 46.21668], [9.95249, 46.38045], [9.73086, 46.35071], [9.71273, 46.29266], [9.57015, 46.2958], [9.46117, 46.37481], [9.45936, 46.50873], [9.40487, 46.46621], [9.36128, 46.5081], [9.28136, 46.49685], [9.25502, 46.43743], [9.29226, 46.32717], [9.24503, 46.23616], [9.01618, 46.04928], [8.99257, 45.9698], [9.09065, 45.89906], [9.06642, 45.8761], [9.04546, 45.84968], [9.04059, 45.8464], [9.03505, 45.83976], [9.03793, 45.83548], [9.03279, 45.82865], [9.0298, 45.82127], [9.00324, 45.82055], [8.99663, 45.83466], [8.9621, 45.83707], [8.94737, 45.84285], [8.91129, 45.8388], [8.93504, 45.86245], [8.94372, 45.86587], [8.93649, 45.86775], [8.88904, 45.95465], [8.86688, 45.96135], [8.85121, 45.97239], [8.8319, 45.9879], [8.79362, 45.99207], [8.78585, 45.98973], [8.79414, 46.00913], [8.85617, 46.0748], [8.80778, 46.10085], [8.75697, 46.10395], [8.62242, 46.12112], [8.45032, 46.26869], [8.46317, 46.43712], [8.42464, 46.46367], [8.30648, 46.41587], [8.31162, 46.38044], [8.08814, 46.26692], [8.16866, 46.17817], [8.11383, 46.11577], [8.02906, 46.10331], [7.98881, 45.99867], [7.9049, 45.99945], [7.85949, 45.91485], [7.56343, 45.97421], [7.10685, 45.85653], [7.04151, 45.92435], [6.95315, 45.85163], [6.80785, 45.83265], [6.80785, 45.71864], [6.98948, 45.63869], [7.00037, 45.509], [7.18019, 45.40071], [7.10572, 45.32924], [7.13115, 45.25386], [7.07074, 45.21228], [6.96706, 45.20841], [6.85144, 45.13226], [6.7697, 45.16044], [6.62803, 45.11175], [6.66981, 45.02324], [6.74791, 45.01939], [6.74519, 44.93661], [6.75518, 44.89915], [6.90774, 44.84322], [6.93499, 44.8664], [7.02217, 44.82519], [7.00401, 44.78782], [7.07484, 44.68073], [7.00582, 44.69364], [6.95133, 44.66264], [6.96042, 44.62129], [6.85507, 44.53072], [6.86233, 44.49834], [6.94504, 44.43112], [6.88784, 44.42043], [6.89171, 44.36637], [6.98221, 44.28289], [7.00764, 44.23736], [7.16929, 44.20352], [7.27827, 44.1462], [7.34547, 44.14359], [7.36364, 44.11882], [7.62155, 44.14881], [7.63245, 44.17877], [7.68694, 44.17487], [7.66878, 44.12795], [7.72508, 44.07578], [7.6597, 44.03009], [7.66848, 43.99943], [7.65266, 43.9763], [7.60771, 43.95772], [7.56858, 43.94506], [7.56075, 43.89932], [7.51162, 43.88301], [7.49355, 43.86551], [7.50423, 43.84345], [7.53006, 43.78405], [7.63035, 43.57419]], [[12.45181, 41.90056], [12.44834, 41.90095], [12.44582, 41.90194], [12.44815, 41.90326], [12.44984, 41.90545], [12.45091, 41.90625], [12.45543, 41.90738], [12.45561, 41.90629], [12.45762, 41.9058], [12.45755, 41.9033], [12.45826, 41.90281], [12.45834, 41.90174], [12.4577, 41.90115], [12.45691, 41.90125], [12.45626, 41.90172], [12.45435, 41.90143], [12.45446, 41.90028], [12.45181, 41.90056]], [[12.45648, 43.89369], [12.44184, 43.90498], [12.41641, 43.89991], [12.40935, 43.9024], [12.41233, 43.90956], [12.40733, 43.92379], [12.41551, 43.92984], [12.41165, 43.93769], [12.40506, 43.94325], [12.40415, 43.95485], [12.41414, 43.95273], [12.42005, 43.9578], [12.43662, 43.95698], [12.44684, 43.96597], [12.46205, 43.97463], [12.47853, 43.98052], [12.49406, 43.98492], [12.50678, 43.99113], [12.51463, 43.99122], [12.5154, 43.98508], [12.51064, 43.98165], [12.51109, 43.97201], [12.50622, 43.97131], [12.50875, 43.96198], [12.50655, 43.95796], [12.51427, 43.94897], [12.51553, 43.94096], [12.50496, 43.93017], [12.50269, 43.92363], [12.49724, 43.92248], [12.49247, 43.91774], [12.49429, 43.90973], [12.48771, 43.89706], [12.45648, 43.89369]]]]
25588 nameEn: "Bailiwick of Jersey",
25590 groups: ["830", "Q185086", "154", "150", "UN"],
25592 roadSpeedUnit: "mph",
25593 roadHeightUnit: "ft",
25594 callingCodes: ["44 01534"]
25597 type: "MultiPolygon",
25598 coordinates: [[[[-2.00491, 48.86706], [-1.83944, 49.23037], [-2.09454, 49.46288], [-2.65349, 49.15373], [-2.00491, 48.86706]]]]
25609 groups: ["029", "003", "419", "019", "UN"],
25611 callingCodes: ["1 876", "1 658"]
25614 type: "MultiPolygon",
25615 coordinates: [[[[-74.09729, 17.36817], [-78.9741, 19.59515], [-78.34606, 16.57862], [-74.09729, 17.36817]]]]
25625 groups: ["145", "142", "UN"],
25626 callingCodes: ["962"]
25629 type: "MultiPolygon",
25630 coordinates: [[[[39.04251, 32.30203], [38.98762, 32.47694], [39.08202, 32.50304], [38.79171, 33.37328], [36.83946, 32.31293], [36.40959, 32.37908], [36.23948, 32.50108], [36.20875, 32.49529], [36.20379, 32.52751], [36.08074, 32.51463], [36.02239, 32.65911], [35.96633, 32.66237], [35.93307, 32.71966], [35.88405, 32.71321], [35.75983, 32.74803], [35.68467, 32.70715], [35.66527, 32.681], [35.61669, 32.67999], [35.59813, 32.65159], [35.56614, 32.64393], [35.57485, 32.48669], [35.55494, 32.42687], [35.55807, 32.38674], [35.57111, 32.21877], [35.52012, 32.04076], [35.54375, 31.96587], [35.52758, 31.9131], [35.55941, 31.76535], [35.47672, 31.49578], [35.40316, 31.25535], [35.43658, 31.12444], [35.41371, 30.95565], [35.33984, 30.8802], [35.33456, 30.81224], [35.29311, 30.71365], [35.21379, 30.60401], [35.19595, 30.50297], [35.16218, 30.43535], [35.19183, 30.34636], [35.14108, 30.07374], [35.02147, 29.66343], [34.98207, 29.58147], [34.97718, 29.54294], [34.92298, 29.45305], [34.8812, 29.36878], [36.07081, 29.18469], [36.50005, 29.49696], [36.75083, 29.86903], [37.4971, 29.99949], [37.66395, 30.33245], [37.99354, 30.49998], [36.99791, 31.50081], [38.99233, 31.99721], [39.29903, 32.23259], [39.26157, 32.35555], [39.04251, 32.30203]]]]
25640 groups: ["030", "142", "UN"],
25642 callingCodes: ["81"]
25645 type: "MultiPolygon",
25646 coordinates: [[[[145.82361, 43.38904], [145.23667, 43.76813], [145.82343, 44.571], [140.9182, 45.92937], [133.61399, 37.41], [129.2669, 34.87122], [122.26612, 25.98197], [123.92912, 17.8782], [155.16731, 23.60141], [145.82361, 43.38904]]]]
25656 groups: ["014", "202", "002", "UN"],
25658 callingCodes: ["254"]
25661 type: "MultiPolygon",
25662 coordinates: [[[[35.9419, 4.61933], [35.51424, 4.61643], [35.42366, 4.76969], [35.47843, 4.91872], [35.30992, 4.90402], [35.34151, 5.02364], [34.47601, 4.72162], [33.9873, 4.23316], [34.06046, 4.15235], [34.15429, 3.80464], [34.45815, 3.67385], [34.44922, 3.51627], [34.39112, 3.48802], [34.41794, 3.44342], [34.40006, 3.37949], [34.45815, 3.18319], [34.56242, 3.11478], [34.60114, 2.93034], [34.65774, 2.8753], [34.73967, 2.85447], [34.78137, 2.76223], [34.77244, 2.70272], [34.95267, 2.47209], [34.90947, 2.42447], [34.98692, 1.97348], [34.9899, 1.6668], [34.92734, 1.56109], [34.87819, 1.5596], [34.7918, 1.36752], [34.82606, 1.30944], [34.82606, 1.26626], [34.80223, 1.22754], [34.67562, 1.21265], [34.58029, 1.14712], [34.57427, 1.09868], [34.52369, 1.10692], [34.43349, 0.85254], [34.40041, 0.80266], [34.31516, 0.75693], [34.27345, 0.63182], [34.20196, 0.62289], [34.13493, 0.58118], [34.11408, 0.48884], [34.08727, 0.44713], [34.10067, 0.36372], [33.90936, 0.10581], [33.98449, -0.13079], [33.9264, -0.54188], [33.93107, -0.99298], [34.02286, -1.00779], [34.03084, -1.05101], [34.0824, -1.02264], [37.67199, -3.06222], [37.71745, -3.304], [37.5903, -3.42735], [37.63099, -3.50723], [37.75036, -3.54243], [37.81321, -3.69179], [39.21631, -4.67835], [39.44306, -4.93877], [39.62121, -4.68136], [41.75542, -1.85308], [41.56362, -1.66375], [41.56, -1.59812], [41.00099, -0.83068], [40.98767, 2.82959], [41.31368, 3.14314], [41.89488, 3.97375], [41.1754, 3.94079], [40.77498, 4.27683], [39.86043, 3.86974], [39.76808, 3.67058], [39.58339, 3.47434], [39.55132, 3.39634], [39.51551, 3.40895], [39.49444, 3.45521], [39.19954, 3.47834], [39.07736, 3.5267], [38.91938, 3.51198], [38.52336, 3.62551], [38.45812, 3.60445], [38.14168, 3.62487], [37.07724, 4.33503], [36.84474, 4.44518], [36.03924, 4.44406], [35.95449, 4.53244], [35.9419, 4.61933]]]]
25671 nameEn: "Kyrgyzstan",
25672 groups: ["143", "142", "UN"],
25673 callingCodes: ["996"]
25676 type: "MultiPolygon",
25677 coordinates: [[[[74.88756, 42.98612], [74.75, 42.99029], [74.70331, 43.02519], [74.64615, 43.05881], [74.57491, 43.13702], [74.22489, 43.24657], [73.55634, 43.03071], [73.50992, 42.82356], [73.44393, 42.43098], [71.88792, 42.83578], [71.62405, 42.76613], [71.53272, 42.8014], [71.2724, 42.77853], [71.22785, 42.69248], [71.17807, 42.67381], [71.15232, 42.60486], [70.97717, 42.50147], [70.85973, 42.30188], [70.94483, 42.26238], [71.13263, 42.28356], [71.28719, 42.18033], [70.69777, 41.92554], [70.17682, 41.5455], [70.48909, 41.40335], [70.67586, 41.47953], [70.78572, 41.36419], [70.77885, 41.24813], [70.86263, 41.23833], [70.9615, 41.16393], [71.02193, 41.19494], [71.11806, 41.15359], [71.25813, 41.18796], [71.27187, 41.11015], [71.34877, 41.16807], [71.40198, 41.09436], [71.46148, 41.13958], [71.43814, 41.19644], [71.46688, 41.31883], [71.57227, 41.29175], [71.6787, 41.42111], [71.65914, 41.49599], [71.73054, 41.54713], [71.71132, 41.43012], [71.76625, 41.4466], [71.83914, 41.3546], [71.91457, 41.2982], [71.85964, 41.19081], [72.07249, 41.11739], [72.10745, 41.15483], [72.16433, 41.16483], [72.17594, 41.15522], [72.14864, 41.13363], [72.1792, 41.10621], [72.21061, 41.05607], [72.17594, 41.02377], [72.18339, 40.99571], [72.324, 41.03381], [72.34026, 41.04539], [72.34757, 41.06104], [72.36138, 41.04384], [72.38511, 41.02785], [72.45206, 41.03018], [72.48742, 40.97136], [72.55109, 40.96046], [72.59136, 40.86947], [72.68157, 40.84942], [72.84291, 40.85512], [72.94454, 40.8094], [73.01869, 40.84681], [73.13267, 40.83512], [73.13412, 40.79122], [73.0612, 40.76678], [72.99133, 40.76457], [72.93296, 40.73089], [72.8722, 40.71111], [72.85372, 40.7116], [72.84754, 40.67229], [72.80137, 40.67856], [72.74866, 40.60873], [72.74894, 40.59592], [72.75982, 40.57273], [72.74862, 40.57131], [72.74768, 40.58051], [72.73995, 40.58409], [72.69579, 40.59778], [72.66713, 40.59076], [72.66713, 40.5219], [72.47795, 40.5532], [72.40517, 40.61917], [72.34406, 40.60144], [72.41714, 40.55736], [72.38384, 40.51535], [72.41513, 40.50856], [72.44191, 40.48222], [72.40346, 40.4007], [72.24368, 40.46091], [72.18648, 40.49893], [71.96401, 40.31907], [72.05464, 40.27586], [71.85002, 40.25647], [71.82646, 40.21872], [71.73054, 40.14818], [71.71719, 40.17886], [71.69621, 40.18492], [71.70569, 40.20391], [71.68386, 40.26984], [71.61931, 40.26775], [71.61725, 40.20615], [71.51549, 40.22986], [71.51215, 40.26943], [71.4246, 40.28619], [71.36663, 40.31593], [71.13042, 40.34106], [71.05901, 40.28765], [70.95789, 40.28761], [70.9818, 40.22392], [70.80495, 40.16813], [70.7928, 40.12797], [70.65827, 40.0981], [70.65946, 39.9878], [70.58912, 39.95211], [70.55033, 39.96619], [70.47557, 39.93216], [70.57384, 39.99394], [70.58297, 40.00891], [70.01283, 40.23288], [69.67001, 40.10639], [69.64704, 40.12165], [69.57615, 40.10524], [69.55555, 40.12296], [69.53794, 40.11833], [69.53855, 40.0887], [69.5057, 40.03277], [69.53615, 39.93991], [69.43557, 39.92877], [69.43134, 39.98431], [69.35649, 40.01994], [69.26938, 39.8127], [69.3594, 39.52516], [69.68677, 39.59281], [69.87491, 39.53882], [70.11111, 39.58223], [70.2869, 39.53141], [70.44757, 39.60128], [70.64087, 39.58792], [70.7854, 39.38933], [71.06418, 39.41586], [71.08752, 39.50704], [71.49814, 39.61397], [71.55856, 39.57588], [71.5517, 39.45722], [71.62688, 39.44056], [71.76816, 39.45456], [71.80164, 39.40631], [71.7522, 39.32031], [71.79202, 39.27355], [71.90601, 39.27674], [72.04059, 39.36704], [72.09689, 39.26823], [72.17242, 39.2661], [72.23834, 39.17248], [72.33173, 39.33093], [72.62027, 39.39696], [72.85934, 39.35116], [73.18454, 39.35536], [73.31912, 39.38615], [73.45096, 39.46677], [73.59831, 39.46425], [73.87018, 39.47879], [73.94683, 39.60733], [73.92354, 39.69565], [73.9051, 39.75073], [73.83006, 39.76136], [73.97049, 40.04378], [74.25533, 40.13191], [74.35063, 40.09742], [74.69875, 40.34668], [74.85996, 40.32857], [74.78168, 40.44886], [74.82013, 40.52197], [75.08243, 40.43945], [75.22834, 40.45382], [75.5854, 40.66874], [75.69663, 40.28642], [75.91361, 40.2948], [75.96168, 40.38064], [76.33659, 40.3482], [76.5261, 40.46114], [76.75681, 40.95354], [76.99302, 41.0696], [77.28004, 41.0033], [77.3693, 41.0375], [77.52723, 41.00227], [77.76206, 41.01574], [77.81287, 41.14307], [78.12873, 41.23091], [78.15757, 41.38565], [78.3732, 41.39603], [79.92977, 42.04113], [80.17842, 42.03211], [80.17807, 42.21166], [79.97364, 42.42816], [79.52921, 42.44778], [79.19763, 42.804], [78.91502, 42.76839], [78.48469, 42.89649], [75.82823, 42.94848], [75.72174, 42.79672], [75.29966, 42.86183], [75.22619, 42.85528], [74.88756, 42.98612]], [[70.74189, 39.86319], [70.63105, 39.77923], [70.59667, 39.83542], [70.54998, 39.85137], [70.52631, 39.86989], [70.53651, 39.89155], [70.74189, 39.86319]], [[71.86463, 39.98598], [71.84316, 39.95582], [71.7504, 39.93701], [71.71511, 39.96348], [71.78838, 40.01404], [71.86463, 39.98598]], [[71.21139, 40.03369], [71.1427, 39.95026], [71.23067, 39.93581], [71.16101, 39.88423], [71.10531, 39.91354], [71.04979, 39.89808], [71.10501, 39.95568], [71.09063, 39.99], [71.11668, 39.99291], [71.11037, 40.01984], [71.01035, 40.05481], [71.00236, 40.18154], [71.06305, 40.1771], [71.12218, 40.03052], [71.21139, 40.03369]]]]
25686 nameEn: "Cambodia",
25687 groups: ["035", "142", "UN"],
25688 callingCodes: ["855"]
25691 type: "MultiPolygon",
25692 coordinates: [[[[105.87328, 11.55953], [105.81645, 11.56876], [105.80867, 11.60536], [105.8507, 11.66635], [105.88962, 11.67854], [105.95188, 11.63738], [106.00792, 11.7197], [106.02038, 11.77457], [106.06708, 11.77761], [106.13158, 11.73283], [106.18539, 11.75171], [106.26478, 11.72122], [106.30525, 11.67549], [106.37219, 11.69836], [106.44691, 11.66787], [106.45158, 11.68616], [106.41577, 11.76999], [106.44535, 11.8279], [106.44068, 11.86294], [106.4687, 11.86751], [106.4111, 11.97413], [106.70687, 11.96956], [106.79405, 12.0807], [106.92325, 12.06548], [106.99953, 12.08983], [107.15831, 12.27547], [107.34511, 12.33327], [107.42917, 12.24657], [107.4463, 12.29373], [107.55059, 12.36824], [107.5755, 12.52177], [107.55993, 12.7982], [107.49611, 12.88926], [107.49144, 13.01215], [107.62843, 13.3668], [107.61909, 13.52577], [107.53503, 13.73908], [107.45252, 13.78897], [107.46498, 13.91593], [107.44318, 13.99751], [107.38247, 13.99147], [107.35757, 14.02319], [107.37158, 14.07906], [107.33577, 14.11832], [107.40427, 14.24509], [107.39493, 14.32655], [107.44941, 14.41552], [107.48521, 14.40346], [107.52569, 14.54665], [107.52102, 14.59034], [107.55371, 14.628], [107.54361, 14.69092], [107.47238, 14.61523], [107.44435, 14.52785], [107.37897, 14.54443], [107.3276, 14.58812], [107.29803, 14.58963], [107.26534, 14.54292], [107.256, 14.48716], [107.21241, 14.48716], [107.17038, 14.41782], [107.09722, 14.3937], [107.03962, 14.45099], [107.04585, 14.41782], [106.98825, 14.36806], [106.9649, 14.3198], [106.90574, 14.33639], [106.8497, 14.29416], [106.80767, 14.31226], [106.73762, 14.42687], [106.63333, 14.44194], [106.59908, 14.50977], [106.57106, 14.50525], [106.54148, 14.59565], [106.50723, 14.58963], [106.45898, 14.55045], [106.47766, 14.50977], [106.43874, 14.52032], [106.40916, 14.45249], [106.32355, 14.44043], [106.25194, 14.48415], [106.21302, 14.36203], [106.00131, 14.36957], [105.99509, 14.32734], [106.02311, 14.30623], [106.04801, 14.20363], [106.10872, 14.18401], [106.11962, 14.11307], [106.18656, 14.06324], [106.16632, 14.01794], [106.10094, 13.98471], [106.10405, 13.9137], [105.90791, 13.92881], [105.78182, 14.02247], [105.78338, 14.08438], [105.5561, 14.15684], [105.44869, 14.10703], [105.36775, 14.09948], [105.2759, 14.17496], [105.20894, 14.34967], [105.17748, 14.34432], [105.14012, 14.23873], [105.08408, 14.20402], [105.02804, 14.23722], [104.97667, 14.38806], [104.69335, 14.42726], [104.55014, 14.36091], [104.27616, 14.39861], [103.93836, 14.3398], [103.70175, 14.38052], [103.71109, 14.4348], [103.53518, 14.42575], [103.39353, 14.35639], [103.16469, 14.33075], [102.93275, 14.19044], [102.91251, 14.01531], [102.77864, 13.93374], [102.72727, 13.77806], [102.56848, 13.69366], [102.5481, 13.6589], [102.58635, 13.6286], [102.62483, 13.60883], [102.57573, 13.60461], [102.5358, 13.56933], [102.44601, 13.5637], [102.36859, 13.57488], [102.33828, 13.55613], [102.361, 13.50551], [102.35563, 13.47307], [102.35692, 13.38274], [102.34611, 13.35618], [102.36001, 13.31142], [102.36146, 13.26006], [102.43422, 13.09061], [102.46011, 13.08057], [102.52275, 12.99813], [102.48694, 12.97537], [102.49335, 12.92711], [102.53053, 12.77506], [102.4994, 12.71736], [102.51963, 12.66117], [102.57567, 12.65358], [102.7796, 12.43781], [102.78116, 12.40284], [102.73134, 12.37091], [102.70176, 12.1686], [102.77026, 12.06815], [102.78427, 11.98746], [102.83957, 11.8519], [102.90973, 11.75613], [102.91449, 11.65512], [102.52395, 11.25257], [102.47649, 9.66162], [103.99198, 10.48391], [104.43778, 10.42386], [104.47963, 10.43046], [104.49869, 10.4057], [104.59018, 10.53073], [104.87933, 10.52833], [104.95094, 10.64003], [105.09571, 10.72722], [105.02722, 10.89236], [105.08326, 10.95656], [105.11449, 10.96332], [105.34011, 10.86179], [105.42884, 10.96878], [105.50045, 10.94586], [105.77751, 11.03671], [105.86376, 10.89839], [105.84603, 10.85873], [105.93403, 10.83853], [105.94535, 10.9168], [106.06708, 10.8098], [106.18539, 10.79451], [106.14301, 10.98176], [106.20095, 10.97795], [106.1757, 11.07301], [106.1527, 11.10476], [106.10444, 11.07879], [105.86782, 11.28343], [105.88962, 11.43605], [105.87328, 11.55953]]]]
25701 nameEn: "Kiribati",
25702 groups: ["057", "009", "UN"],
25704 callingCodes: ["686"]
25707 type: "MultiPolygon",
25708 coordinates: [[[[169, 3.9], [169, -3.5], [178, -3.5], [178, 3.9], [169, 3.9]]], [[[-161.06795, 5.2462], [-158.12991, -1.86122], [-175.33482, -1.40631], [-175.31804, -7.54825], [-156.50903, -7.4975], [-156.48634, -15.52824], [-135.59706, -4.70473], [-161.06795, 5.2462]]]]
25718 groups: ["014", "202", "002", "UN"],
25719 callingCodes: ["269"]
25722 type: "MultiPolygon",
25723 coordinates: [[[[42.63904, -10.02522], [43.28731, -13.97126], [45.4971, -11.75965], [42.63904, -10.02522]]]]
25732 nameEn: "St. Kitts and Nevis",
25733 groups: ["029", "003", "419", "019", "UN"],
25735 roadSpeedUnit: "mph",
25736 callingCodes: ["1 869"]
25739 type: "MultiPolygon",
25740 coordinates: [[[[-62.29333, 17.43155], [-62.76692, 17.64353], [-63.09677, 17.21372], [-62.63813, 16.65446], [-62.29333, 17.43155]]]]
25749 nameEn: "North Korea",
25750 groups: ["030", "142", "UN"],
25751 callingCodes: ["850"]
25754 type: "MultiPolygon",
25755 coordinates: [[[[130.26095, 42.9027], [130.09764, 42.91425], [130.12957, 42.98361], [129.96409, 42.97306], [129.95082, 43.01051], [129.8865, 43.00395], [129.85261, 42.96494], [129.83277, 42.86746], [129.80719, 42.79218], [129.7835, 42.76521], [129.77183, 42.69435], [129.75294, 42.59409], [129.72541, 42.43739], [129.60482, 42.44461], [129.54701, 42.37254], [129.42882, 42.44702], [129.28541, 42.41574], [129.22423, 42.3553], [129.22285, 42.26491], [129.15178, 42.17224], [128.96068, 42.06657], [128.94007, 42.03537], [128.04487, 42.01769], [128.15119, 41.74568], [128.30716, 41.60322], [128.20061, 41.40895], [128.18546, 41.41279], [128.12967, 41.37931], [128.03311, 41.39232], [128.02633, 41.42103], [127.92943, 41.44291], [127.29712, 41.49473], [127.17841, 41.59714], [126.90729, 41.79955], [126.60631, 41.65565], [126.53189, 41.35206], [126.242, 41.15454], [126.00335, 40.92835], [125.76869, 40.87908], [125.71172, 40.85223], [124.86913, 40.45387], [124.40719, 40.13655], [124.38556, 40.11047], [124.3322, 40.05573], [124.37089, 40.03004], [124.35029, 39.95639], [124.23201, 39.9248], [124.17532, 39.8232], [123.90497, 38.79949], [123.85601, 37.49093], [124.67666, 38.05679], [124.84224, 37.977], [124.87921, 37.80827], [125.06408, 37.66334], [125.37112, 37.62643], [125.81159, 37.72949], [126.13074, 37.70512], [126.18776, 37.74728], [126.19097, 37.81462], [126.24402, 37.83113], [126.43239, 37.84095], [126.46818, 37.80873], [126.56709, 37.76857], [126.59918, 37.76364], [126.66067, 37.7897], [126.68793, 37.83728], [126.68793, 37.9175], [126.67023, 37.95852], [126.84961, 38.0344], [126.88106, 38.10246], [126.95887, 38.1347], [126.95338, 38.17735], [127.04479, 38.25518], [127.15749, 38.30722], [127.38727, 38.33227], [127.49672, 38.30647], [127.55013, 38.32257], [128.02917, 38.31861], [128.27652, 38.41657], [128.31105, 38.58462], [128.37487, 38.62345], [128.65655, 38.61914], [131.95041, 41.5445], [130.65022, 42.32281], [130.66367, 42.38024], [130.64181, 42.41422], [130.60805, 42.4317], [130.56835, 42.43281], [130.55143, 42.52158], [130.50123, 42.61636], [130.44361, 42.54849], [130.41826, 42.6011], [130.2385, 42.71127], [130.23068, 42.80125], [130.26095, 42.9027]]]]
25764 nameEn: "South Korea",
25765 groups: ["030", "142", "UN"],
25766 callingCodes: ["82"]
25769 type: "MultiPolygon",
25770 coordinates: [[[[133.11729, 37.53115], [128.65655, 38.61914], [128.37487, 38.62345], [128.31105, 38.58462], [128.27652, 38.41657], [128.02917, 38.31861], [127.55013, 38.32257], [127.49672, 38.30647], [127.38727, 38.33227], [127.15749, 38.30722], [127.04479, 38.25518], [126.95338, 38.17735], [126.95887, 38.1347], [126.88106, 38.10246], [126.84961, 38.0344], [126.67023, 37.95852], [126.68793, 37.9175], [126.68793, 37.83728], [126.66067, 37.7897], [126.59918, 37.76364], [126.56709, 37.76857], [126.46818, 37.80873], [126.43239, 37.84095], [126.24402, 37.83113], [126.19097, 37.81462], [126.18776, 37.74728], [126.13074, 37.70512], [125.81159, 37.72949], [125.37112, 37.62643], [125.06408, 37.66334], [124.87921, 37.80827], [124.84224, 37.977], [124.67666, 38.05679], [123.85601, 37.49093], [122.80525, 33.30571], [125.99728, 32.63328], [129.2669, 34.87122], [133.11729, 37.53115]]]]
25780 groups: ["145", "142", "UN"],
25781 callingCodes: ["965"]
25784 type: "MultiPolygon",
25785 coordinates: [[[[49.00421, 28.81495], [48.59531, 29.66815], [48.40479, 29.85763], [48.17332, 30.02448], [48.06782, 30.02906], [48.01114, 29.98906], [47.7095, 30.10453], [47.37192, 30.10421], [47.15166, 30.01044], [46.89695, 29.50584], [46.5527, 29.10283], [47.46202, 29.0014], [47.58376, 28.83382], [47.59863, 28.66798], [47.70561, 28.5221], [48.42991, 28.53628], [49.00421, 28.81495]]]]
25794 nameEn: "Cayman Islands",
25796 groups: ["BOTS", "029", "003", "419", "019", "UN"],
25798 roadSpeedUnit: "mph",
25799 roadHeightUnit: "ft",
25800 callingCodes: ["1 345"]
25803 type: "MultiPolygon",
25804 coordinates: [[[[-82.11509, 19.60401], [-80.36068, 18.11751], [-79.32727, 20.06742], [-82.11509, 19.60401]]]]
25813 nameEn: "Kazakhstan",
25814 groups: ["143", "142", "UN"],
25815 callingCodes: ["7"]
25818 type: "MultiPolygon",
25819 coordinates: [[[[68.90865, 55.38148], [68.19206, 55.18823], [68.26661, 55.09226], [68.21308, 54.98645], [65.20174, 54.55216], [65.24663, 54.35721], [65.11033, 54.33028], [64.97216, 54.4212], [63.97686, 54.29763], [64.02715, 54.22679], [63.91224, 54.20013], [63.80604, 54.27079], [62.58651, 54.05871], [62.56876, 53.94047], [62.45931, 53.90737], [62.38535, 54.03961], [62.00966, 54.04134], [62.03913, 53.94768], [61.65318, 54.02445], [61.56941, 53.95703], [61.47603, 54.08048], [61.3706, 54.08464], [61.26863, 53.92797], [60.99796, 53.93699], [61.14283, 53.90063], [61.22574, 53.80268], [60.90626, 53.62937], [61.55706, 53.57144], [61.57185, 53.50112], [61.37957, 53.45887], [61.29082, 53.50992], [61.14291, 53.41481], [61.19024, 53.30536], [62.14574, 53.09626], [62.12799, 52.99133], [62.0422, 52.96105], [61.23462, 53.03227], [61.05842, 52.92217], [60.71989, 52.75923], [60.71693, 52.66245], [60.84118, 52.63912], [60.84709, 52.52228], [60.98021, 52.50068], [61.05417, 52.35096], [60.78201, 52.22067], [60.72581, 52.15538], [60.48915, 52.15175], [60.19925, 51.99173], [59.99809, 51.98263], [60.09867, 51.87135], [60.50986, 51.7964], [60.36787, 51.66815], [60.5424, 51.61675], [60.92401, 51.61124], [60.95655, 51.48615], [61.50677, 51.40687], [61.55114, 51.32746], [61.6813, 51.25716], [61.56889, 51.23679], [61.4431, 50.80679], [60.81833, 50.6629], [60.31914, 50.67705], [60.17262, 50.83312], [60.01288, 50.8163], [59.81172, 50.54451], [59.51886, 50.49937], [59.48928, 50.64216], [58.87974, 50.70852], [58.3208, 51.15151], [57.75578, 51.13852], [57.74986, 50.93017], [57.44221, 50.88354], [57.17302, 51.11253], [56.17906, 50.93204], [56.11398, 50.7471], [55.67774, 50.54508], [54.72067, 51.03261], [54.56685, 51.01958], [54.71476, 50.61214], [54.55797, 50.52006], [54.41894, 50.61214], [54.46331, 50.85554], [54.12248, 51.11542], [53.69299, 51.23466], [53.46165, 51.49445], [52.54329, 51.48444], [52.36119, 51.74161], [51.8246, 51.67916], [51.77431, 51.49536], [51.301, 51.48799], [51.26254, 51.68466], [50.59695, 51.61859], [50.26859, 51.28677], [49.97277, 51.2405], [49.76866, 51.11067], [49.39001, 51.09396], [49.41959, 50.85927], [49.12673, 50.78639], [48.86936, 50.61589], [48.57946, 50.63278], [48.90782, 50.02281], [48.68352, 49.89546], [48.42564, 49.82283], [48.24519, 49.86099], [48.10044, 50.09242], [47.58551, 50.47867], [47.30448, 50.30894], [47.34589, 50.09308], [47.18319, 49.93721], [46.9078, 49.86707], [46.78398, 49.34026], [47.04658, 49.19834], [47.00857, 49.04921], [46.78392, 48.95352], [46.49011, 48.43019], [47.11516, 48.27188], [47.12107, 47.83687], [47.38731, 47.68176], [47.41689, 47.83687], [47.64973, 47.76559], [48.15348, 47.74545], [48.45173, 47.40818], [48.52326, 47.4102], [49.01136, 46.72716], [48.51142, 46.69268], [48.54988, 46.56267], [49.16518, 46.38542], [49.32259, 46.26944], [49.88945, 46.04554], [49.2134, 44.84989], [52.26048, 41.69249], [52.47884, 41.78034], [52.97575, 42.1308], [54.20635, 42.38477], [54.95182, 41.92424], [55.45471, 41.25609], [56.00314, 41.32584], [55.97584, 44.99322], [55.97584, 44.99328], [55.97584, 44.99338], [55.97584, 44.99343], [55.97584, 44.99348], [55.97584, 44.99353], [55.97584, 44.99359], [55.97584, 44.99369], [55.97584, 44.99374], [55.97584, 44.99384], [55.97584, 44.9939], [55.97584, 44.994], [55.97584, 44.99405], [55.97584, 44.99415], [55.97584, 44.99421], [55.97584, 44.99426], [55.97584, 44.99431], [55.97584, 44.99436], [55.97584, 44.99441], [55.97594, 44.99446], [55.97605, 44.99452], [55.97605, 44.99457], [55.97605, 44.99462], [55.97605, 44.99467], [55.97605, 44.99477], [55.97615, 44.99477], [55.97615, 44.99483], [55.97615, 44.99493], [55.97615, 44.99498], [55.97615, 44.99503], [55.97615, 44.99508], [55.97625, 44.99514], [55.97636, 44.99519], [55.97636, 44.99524], [55.97646, 44.99529], [55.97646, 44.99534], [55.97656, 44.99539], [55.97667, 44.99545], [55.97677, 44.9955], [55.97677, 44.99555], [55.97677, 44.9956], [55.97687, 44.9956], [55.97698, 44.99565], [55.97698, 44.9957], [55.97708, 44.99576], [55.97718, 44.99581], [55.97729, 44.99586], [55.97739, 44.99586], [55.97739, 44.99591], [55.97749, 44.99591], [55.9776, 44.99591], [55.9777, 44.99596], [55.9777, 44.99601], [55.9778, 44.99607], [55.97791, 44.99607], [55.97801, 44.99607], [55.97801, 44.99612], [55.97811, 44.99617], [55.97822, 44.99617], [55.97832, 44.99622], [55.97842, 44.99622], [58.59711, 45.58671], [61.01475, 44.41383], [62.01711, 43.51008], [63.34656, 43.64003], [64.53885, 43.56941], [64.96464, 43.74748], [65.18666, 43.48835], [65.53277, 43.31856], [65.85194, 42.85481], [66.09482, 42.93426], [66.00546, 41.94455], [66.53302, 41.87388], [66.69129, 41.1311], [67.9644, 41.14611], [67.98511, 41.02794], [68.08273, 41.08148], [68.1271, 41.0324], [67.96736, 40.83798], [68.49983, 40.56437], [68.63, 40.59358], [68.58444, 40.91447], [68.49983, 40.99669], [68.62221, 41.03019], [68.65662, 40.93861], [68.73945, 40.96989], [68.7217, 41.05025], [69.01308, 41.22804], [69.05006, 41.36183], [69.15137, 41.43078], [69.17701, 41.43769], [69.18528, 41.45175], [69.20439, 41.45391], [69.22671, 41.46298], [69.23332, 41.45847], [69.25059, 41.46693], [69.29778, 41.43673], [69.35554, 41.47211], [69.37468, 41.46555], [69.45081, 41.46246], [69.39485, 41.51518], [69.45751, 41.56863], [69.49545, 41.545], [70.94483, 42.26238], [70.85973, 42.30188], [70.97717, 42.50147], [71.15232, 42.60486], [71.17807, 42.67381], [71.22785, 42.69248], [71.2724, 42.77853], [71.53272, 42.8014], [71.62405, 42.76613], [71.88792, 42.83578], [73.44393, 42.43098], [73.50992, 42.82356], [73.55634, 43.03071], [74.22489, 43.24657], [74.57491, 43.13702], [74.64615, 43.05881], [74.70331, 43.02519], [74.75, 42.99029], [74.88756, 42.98612], [75.22619, 42.85528], [75.29966, 42.86183], [75.72174, 42.79672], [75.82823, 42.94848], [78.48469, 42.89649], [78.91502, 42.76839], [79.19763, 42.804], [79.52921, 42.44778], [79.97364, 42.42816], [80.17807, 42.21166], [80.26841, 42.23797], [80.16892, 42.61137], [80.26886, 42.8366], [80.38169, 42.83142], [80.58999, 42.9011], [80.3735, 43.01557], [80.62913, 43.141], [80.78817, 43.14235], [80.77771, 43.30065], [80.69718, 43.32589], [80.75156, 43.44948], [80.40031, 44.10986], [80.40229, 44.23319], [80.38384, 44.63073], [79.8987, 44.89957], [80.11169, 45.03352], [81.73278, 45.3504], [82.51374, 45.1755], [82.58474, 45.40027], [82.21792, 45.56619], [83.04622, 47.19053], [83.92184, 46.98912], [84.73077, 47.01394], [84.93995, 46.87399], [85.22443, 47.04816], [85.54294, 47.06171], [85.69696, 47.2898], [85.61067, 47.49753], [85.5169, 48.05493], [85.73581, 48.3939], [86.38069, 48.46064], [86.75343, 48.70331], [86.73568, 48.99918], [86.87238, 49.12432], [87.28386, 49.11626], [87.31465, 49.23603], [87.03071, 49.25142], [86.82606, 49.51796], [86.61307, 49.60239], [86.79056, 49.74787], [86.63674, 49.80136], [86.18709, 49.50259], [85.24047, 49.60239], [84.99198, 50.06793], [84.29385, 50.27257], [83.8442, 50.87375], [83.14607, 51.00796], [82.55443, 50.75412], [81.94999, 50.79307], [81.46581, 50.77658], [81.41248, 50.97524], [81.06091, 50.94833], [81.16999, 51.15662], [80.80318, 51.28262], [80.44819, 51.20855], [80.4127, 50.95581], [80.08138, 50.77658], [79.11255, 52.01171], [77.90383, 53.29807], [76.54243, 53.99329], [76.44076, 54.16017], [76.82266, 54.1798], [76.91052, 54.4677], [75.3668, 54.07439], [75.43398, 53.98652], [75.07405, 53.80831], [73.39218, 53.44623], [73.25412, 53.61532], [73.68921, 53.86522], [73.74778, 54.07194], [73.37963, 53.96132], [72.71026, 54.1161], [72.43415, 53.92685], [72.17477, 54.36303], [71.96141, 54.17736], [71.10379, 54.13326], [71.08706, 54.33376], [71.24185, 54.64965], [71.08288, 54.71253], [70.96009, 55.10558], [70.76493, 55.3027], [70.19179, 55.1476], [69.74917, 55.35545], [69.34224, 55.36344], [68.90865, 55.38148]]]]
25829 groups: ["035", "142", "UN"],
25830 callingCodes: ["856"]
25833 type: "MultiPolygon",
25834 coordinates: [[[[102.1245, 22.43372], [102.03633, 22.46164], [101.98487, 22.42766], [101.91344, 22.44417], [101.90714, 22.38688], [101.86828, 22.38397], [101.7685, 22.50337], [101.68973, 22.46843], [101.61306, 22.27515], [101.56789, 22.28876], [101.53638, 22.24794], [101.60675, 22.13513], [101.57525, 22.13026], [101.62566, 21.96574], [101.7791, 21.83019], [101.74555, 21.72852], [101.83257, 21.61562], [101.80001, 21.57461], [101.7475, 21.5873], [101.7727, 21.51794], [101.74224, 21.48276], [101.74014, 21.30967], [101.84412, 21.25291], [101.83887, 21.20983], [101.76745, 21.21571], [101.79266, 21.19025], [101.7622, 21.14813], [101.70548, 21.14911], [101.66977, 21.20004], [101.60886, 21.17947], [101.59491, 21.18621], [101.6068, 21.23329], [101.54563, 21.25668], [101.29326, 21.17254], [101.2229, 21.23271], [101.26912, 21.36482], [101.19349, 21.41959], [101.2124, 21.56422], [101.15156, 21.56129], [101.16198, 21.52808], [101.00234, 21.39612], [100.80173, 21.2934], [100.72716, 21.31786], [100.63578, 21.05639], [100.55281, 21.02796], [100.50974, 20.88574], [100.64628, 20.88279], [100.60112, 20.8347], [100.51079, 20.82194], [100.36375, 20.82783], [100.1957, 20.68247], [100.08404, 20.36626], [100.09999, 20.31614], [100.09337, 20.26293], [100.11785, 20.24787], [100.1712, 20.24324], [100.16668, 20.2986], [100.22076, 20.31598], [100.25769, 20.3992], [100.33383, 20.4028], [100.37439, 20.35156], [100.41473, 20.25625], [100.44992, 20.23644], [100.4537, 20.19971], [100.47567, 20.19133], [100.51052, 20.14928], [100.55218, 20.17741], [100.58808, 20.15791], [100.5094, 19.87904], [100.398, 19.75047], [100.49604, 19.53504], [100.58219, 19.49164], [100.64606, 19.55884], [100.77231, 19.48324], [100.90302, 19.61901], [101.08928, 19.59748], [101.26545, 19.59242], [101.26991, 19.48324], [101.21347, 19.46223], [101.20604, 19.35296], [101.24911, 19.33334], [101.261, 19.12717], [101.35606, 19.04716], [101.25803, 18.89545], [101.22832, 18.73377], [101.27585, 18.68875], [101.06047, 18.43247], [101.18227, 18.34367], [101.15108, 18.25624], [101.19118, 18.2125], [101.1793, 18.0544], [101.02185, 17.87637], [100.96541, 17.57926], [101.15108, 17.47586], [101.44667, 17.7392], [101.72294, 17.92867], [101.78087, 18.07559], [101.88485, 18.02474], [102.11359, 18.21532], [102.45523, 17.97106], [102.59234, 17.96127], [102.60971, 17.95411], [102.61432, 17.92273], [102.5896, 17.84889], [102.59485, 17.83537], [102.68194, 17.80151], [102.69946, 17.81686], [102.67543, 17.84529], [102.68538, 17.86653], [102.75954, 17.89561], [102.79044, 17.93612], [102.81988, 17.94233], [102.86323, 17.97531], [102.95812, 18.0054], [102.9912, 17.9949], [103.01998, 17.97095], [103.0566, 18.00144], [103.07823, 18.03833], [103.07343, 18.12351], [103.1493, 18.17799], [103.14994, 18.23172], [103.17093, 18.2618], [103.29757, 18.30475], [103.23818, 18.34875], [103.24779, 18.37807], [103.30977, 18.4341], [103.41044, 18.4486], [103.47773, 18.42841], [103.60957, 18.40528], [103.699, 18.34125], [103.82449, 18.33979], [103.85642, 18.28666], [103.93916, 18.33914], [103.97725, 18.33631], [104.06533, 18.21656], [104.10927, 18.10826], [104.21776, 17.99335], [104.2757, 17.86139], [104.35432, 17.82871], [104.45404, 17.66788], [104.69867, 17.53038], [104.80061, 17.39367], [104.80716, 17.19025], [104.73712, 17.01404], [104.7373, 16.91125], [104.76442, 16.84752], [104.7397, 16.81005], [104.76099, 16.69302], [104.73349, 16.565], [104.88057, 16.37311], [105.00262, 16.25627], [105.06204, 16.09792], [105.42001, 16.00657], [105.38508, 15.987], [105.34115, 15.92737], [105.37959, 15.84074], [105.42285, 15.76971], [105.46573, 15.74742], [105.61756, 15.68792], [105.60446, 15.53301], [105.58191, 15.41031], [105.47635, 15.3796], [105.4692, 15.33709], [105.50662, 15.32054], [105.58043, 15.32724], [105.46661, 15.13132], [105.61162, 15.00037], [105.5121, 14.80802], [105.53864, 14.55731], [105.43783, 14.43865], [105.20894, 14.34967], [105.2759, 14.17496], [105.36775, 14.09948], [105.44869, 14.10703], [105.5561, 14.15684], [105.78338, 14.08438], [105.78182, 14.02247], [105.90791, 13.92881], [106.10405, 13.9137], [106.10094, 13.98471], [106.16632, 14.01794], [106.18656, 14.06324], [106.11962, 14.11307], [106.10872, 14.18401], [106.04801, 14.20363], [106.02311, 14.30623], [105.99509, 14.32734], [106.00131, 14.36957], [106.21302, 14.36203], [106.25194, 14.48415], [106.32355, 14.44043], [106.40916, 14.45249], [106.43874, 14.52032], [106.47766, 14.50977], [106.45898, 14.55045], [106.50723, 14.58963], [106.54148, 14.59565], [106.57106, 14.50525], [106.59908, 14.50977], [106.63333, 14.44194], [106.73762, 14.42687], [106.80767, 14.31226], [106.8497, 14.29416], [106.90574, 14.33639], [106.9649, 14.3198], [106.98825, 14.36806], [107.04585, 14.41782], [107.03962, 14.45099], [107.09722, 14.3937], [107.17038, 14.41782], [107.21241, 14.48716], [107.256, 14.48716], [107.26534, 14.54292], [107.29803, 14.58963], [107.3276, 14.58812], [107.37897, 14.54443], [107.44435, 14.52785], [107.47238, 14.61523], [107.54361, 14.69092], [107.51579, 14.79282], [107.59285, 14.87795], [107.48277, 14.93751], [107.46516, 15.00982], [107.61486, 15.0566], [107.61926, 15.13949], [107.58844, 15.20111], [107.62587, 15.2266], [107.60605, 15.37524], [107.62367, 15.42193], [107.53341, 15.40496], [107.50699, 15.48771], [107.3815, 15.49832], [107.34408, 15.62345], [107.27583, 15.62769], [107.27143, 15.71459], [107.21859, 15.74638], [107.21419, 15.83747], [107.34188, 15.89464], [107.39471, 15.88829], [107.46296, 16.01106], [107.44975, 16.08511], [107.33968, 16.05549], [107.25822, 16.13587], [107.14595, 16.17816], [107.15035, 16.26271], [107.09091, 16.3092], [107.02597, 16.31132], [106.97385, 16.30204], [106.96638, 16.34938], [106.88067, 16.43594], [106.88727, 16.52671], [106.84104, 16.55415], [106.74418, 16.41904], [106.65832, 16.47816], [106.66052, 16.56892], [106.61477, 16.60713], [106.58267, 16.6012], [106.59013, 16.62259], [106.55485, 16.68704], [106.55265, 16.86831], [106.52183, 16.87884], [106.51963, 16.92097], [106.54824, 16.92729], [106.55045, 17.0031], [106.50862, 16.9673], [106.43597, 17.01362], [106.31929, 17.20509], [106.29287, 17.3018], [106.24444, 17.24714], [106.18991, 17.28227], [106.09019, 17.36399], [105.85744, 17.63221], [105.76612, 17.67147], [105.60381, 17.89356], [105.64784, 17.96687], [105.46292, 18.22008], [105.38366, 18.15315], [105.15942, 18.38691], [105.10408, 18.43533], [105.1327, 18.58355], [105.19654, 18.64196], [105.12829, 18.70453], [104.64617, 18.85668], [104.5361, 18.97747], [103.87125, 19.31854], [104.06058, 19.43484], [104.10832, 19.51575], [104.05617, 19.61743], [104.06498, 19.66926], [104.23229, 19.70242], [104.41281, 19.70035], [104.53169, 19.61743], [104.64837, 19.62365], [104.68359, 19.72729], [104.8355, 19.80395], [104.8465, 19.91783], [104.9874, 20.09573], [104.91695, 20.15567], [104.86852, 20.14121], [104.61315, 20.24452], [104.62195, 20.36633], [104.72102, 20.40554], [104.66158, 20.47774], [104.47886, 20.37459], [104.40621, 20.3849], [104.38199, 20.47155], [104.63957, 20.6653], [104.27412, 20.91433], [104.11121, 20.96779], [103.98024, 20.91531], [103.82282, 20.8732], [103.73478, 20.6669], [103.68633, 20.66324], [103.45737, 20.82382], [103.38032, 20.79501], [103.21497, 20.89832], [103.12055, 20.89994], [103.03469, 21.05821], [102.97745, 21.05821], [102.89825, 21.24707], [102.80794, 21.25736], [102.88939, 21.3107], [102.94223, 21.46034], [102.86297, 21.4255], [102.98846, 21.58936], [102.97965, 21.74076], [102.86077, 21.71213], [102.85637, 21.84501], [102.81894, 21.83888], [102.82115, 21.73667], [102.74189, 21.66713], [102.67145, 21.65894], [102.62301, 21.91447], [102.49092, 21.99002], [102.51734, 22.02676], [102.18712, 22.30403], [102.14099, 22.40092], [102.1245, 22.43372]]]]
25845 groups: ["145", "142", "UN"],
25846 callingCodes: ["961"]
25849 type: "MultiPolygon",
25850 coordinates: [[[[35.94816, 33.47886], [35.94465, 33.52774], [36.05723, 33.57904], [35.9341, 33.6596], [36.06778, 33.82927], [36.14517, 33.85118], [36.3967, 33.83365], [36.38263, 33.86579], [36.28589, 33.91981], [36.41078, 34.05253], [36.50576, 34.05982], [36.5128, 34.09916], [36.62537, 34.20251], [36.59195, 34.2316], [36.58667, 34.27667], [36.60778, 34.31009], [36.56556, 34.31881], [36.53039, 34.3798], [36.55853, 34.41609], [36.46179, 34.46541], [36.4442, 34.50165], [36.34745, 34.5002], [36.3369, 34.52629], [36.39846, 34.55672], [36.41429, 34.61175], [36.45299, 34.59438], [36.46003, 34.6378], [36.42941, 34.62505], [36.35384, 34.65447], [36.35135, 34.68516], [36.32399, 34.69334], [36.29165, 34.62991], [35.98718, 34.64977], [35.97386, 34.63322], [35.48515, 34.70851], [34.78515, 33.20368], [35.10645, 33.09318], [35.1924, 33.08743], [35.31429, 33.10515], [35.35223, 33.05617], [35.43059, 33.06659], [35.448, 33.09264], [35.50272, 33.09056], [35.50335, 33.114], [35.52573, 33.11921], [35.54228, 33.19865], [35.5362, 33.23196], [35.54808, 33.236], [35.54544, 33.25513], [35.55555, 33.25844], [35.56523, 33.28969], [35.58326, 33.28381], [35.58502, 33.26653], [35.62283, 33.24226], [35.62019, 33.27278], [35.77477, 33.33609], [35.81324, 33.36354], [35.82577, 33.40479], [35.88668, 33.43183], [35.94816, 33.47886]]]]
25859 nameEn: "St. Lucia",
25861 groups: ["029", "003", "419", "019", "UN"],
25863 roadSpeedUnit: "mph",
25864 callingCodes: ["1 758"]
25867 type: "MultiPolygon",
25868 coordinates: [[[[-59.95997, 14.20285], [-61.69315, 14.26451], [-59.94058, 12.34011], [-59.95997, 14.20285]]]]
25877 nameEn: "Liechtenstein",
25879 groups: ["155", "150", "UN"],
25880 callingCodes: ["423"]
25883 type: "MultiPolygon",
25884 coordinates: [[[[9.60717, 47.06091], [9.61216, 47.07732], [9.63395, 47.08443], [9.62623, 47.14685], [9.56539, 47.17124], [9.58264, 47.20673], [9.56981, 47.21926], [9.55176, 47.22585], [9.56766, 47.24281], [9.53116, 47.27029], [9.52406, 47.24959], [9.50318, 47.22153], [9.4891, 47.19346], [9.48774, 47.17402], [9.51044, 47.13727], [9.52089, 47.10019], [9.51362, 47.08505], [9.47139, 47.06402], [9.47548, 47.05257], [9.54041, 47.06495], [9.55721, 47.04762], [9.60717, 47.06091]]]]
25893 nameEn: "Sri Lanka",
25894 groups: ["034", "142", "UN"],
25896 callingCodes: ["94"]
25899 type: "MultiPolygon",
25900 coordinates: [[[[76.59015, 5.591], [85.15017, 5.21497], [80.48418, 10.20786], [79.42124, 9.80115], [79.50447, 8.91876], [76.59015, 5.591]]]]
25910 groups: ["011", "202", "002", "UN"],
25911 callingCodes: ["231"]
25914 type: "MultiPolygon",
25915 coordinates: [[[[-8.47114, 7.55676], [-8.55874, 7.62525], [-8.55874, 7.70167], [-8.67814, 7.69428], [-8.72789, 7.51429], [-8.8448, 7.35149], [-8.85724, 7.26019], [-8.93435, 7.2824], [-9.09107, 7.1985], [-9.18311, 7.30461], [-9.20798, 7.38109], [-9.305, 7.42056], [-9.41943, 7.41809], [-9.48161, 7.37122], [-9.37465, 7.62032], [-9.35724, 7.74111], [-9.44928, 7.9284], [-9.41445, 8.02448], [-9.50898, 8.18455], [-9.47415, 8.35195], [-9.77763, 8.54633], [-10.05873, 8.42578], [-10.05375, 8.50697], [-10.14579, 8.52665], [-10.203, 8.47991], [-10.27575, 8.48711], [-10.30084, 8.30008], [-10.31635, 8.28554], [-10.29839, 8.21283], [-10.35227, 8.15223], [-10.45023, 8.15627], [-10.51554, 8.1393], [-10.57523, 8.04829], [-10.60492, 8.04072], [-10.60422, 7.7739], [-11.29417, 7.21576], [-11.4027, 6.97746], [-11.50429, 6.92704], [-12.15048, 6.15992], [-7.52774, 3.7105], [-7.53259, 4.35145], [-7.59349, 4.8909], [-7.53876, 4.94294], [-7.55369, 5.08667], [-7.48901, 5.14118], [-7.46165, 5.26256], [-7.36463, 5.32944], [-7.43428, 5.42355], [-7.37209, 5.61173], [-7.43926, 5.74787], [-7.43677, 5.84687], [-7.46165, 5.84934], [-7.48155, 5.80974], [-7.67309, 5.94337], [-7.70294, 5.90625], [-7.78254, 5.99037], [-7.79747, 6.07696], [-7.8497, 6.08932], [-7.83478, 6.20309], [-7.90692, 6.27728], [-8.00642, 6.31684], [-8.17557, 6.28222], [-8.3298, 6.36381], [-8.38453, 6.35887], [-8.45666, 6.49977], [-8.48652, 6.43797], [-8.59456, 6.50612], [-8.31736, 6.82837], [-8.29249, 7.1691], [-8.37458, 7.25794], [-8.41935, 7.51203], [-8.47114, 7.55676]]]]
25925 groups: ["018", "202", "002", "UN"],
25927 callingCodes: ["266"]
25930 type: "MultiPolygon",
25931 coordinates: [[[[29.33204, -29.45598], [29.44883, -29.3772], [29.40524, -29.21246], [28.68043, -28.58744], [28.65091, -28.57025], [28.40612, -28.6215], [28.30518, -28.69531], [28.2348, -28.69471], [28.1317, -28.7293], [28.02503, -28.85991], [27.98675, -28.8787], [27.9392, -28.84864], [27.88933, -28.88156], [27.8907, -28.91612], [27.75458, -28.89839], [27.55974, -29.18954], [27.5158, -29.2261], [27.54258, -29.25575], [27.48679, -29.29349], [27.45125, -29.29708], [27.47254, -29.31968], [27.4358, -29.33465], [27.33464, -29.48161], [27.01016, -29.65439], [27.09489, -29.72796], [27.22719, -30.00718], [27.29603, -30.05473], [27.32555, -30.14785], [27.40778, -30.14577], [27.37293, -30.19401], [27.36649, -30.27246], [27.38108, -30.33456], [27.45452, -30.32239], [27.56901, -30.42504], [27.56781, -30.44562], [27.62137, -30.50509], [27.6521, -30.51707], [27.67819, -30.53437], [27.69467, -30.55862], [27.74814, -30.60635], [28.12073, -30.68072], [28.2319, -30.28476], [28.399, -30.1592], [28.68627, -30.12885], [28.80222, -30.10579], [28.9338, -30.05072], [29.16548, -29.91706], [29.12553, -29.76266], [29.28545, -29.58456], [29.33204, -29.45598]]]]
25940 nameEn: "Lithuania",
25941 groups: ["EU", "154", "150", "UN"],
25942 callingCodes: ["370"]
25945 type: "MultiPolygon",
25946 coordinates: [[[[24.89005, 56.46666], [24.83686, 56.41565], [24.70022, 56.40483], [24.57353, 56.31525], [24.58143, 56.29125], [24.42746, 56.26522], [24.32334, 56.30226], [24.13139, 56.24881], [24.02657, 56.3231], [23.75726, 56.37282], [23.49803, 56.34307], [23.40486, 56.37689], [23.31606, 56.3827], [23.17312, 56.36795], [23.09531, 56.30511], [22.96988, 56.41213], [22.83048, 56.367], [22.69354, 56.36284], [22.56441, 56.39305], [22.3361, 56.4016], [22.09728, 56.42851], [22.00548, 56.41508], [21.74558, 56.33181], [21.57888, 56.31406], [21.49736, 56.29106], [21.24644, 56.16917], [21.15016, 56.07818], [20.68447, 56.04073], [20.60454, 55.40986], [20.95181, 55.27994], [21.26425, 55.24456], [21.35465, 55.28427], [21.38446, 55.29348], [21.46766, 55.21115], [21.51095, 55.18507], [21.55605, 55.20311], [21.64954, 55.1791], [21.85521, 55.09493], [21.96505, 55.07353], [21.99543, 55.08691], [22.03984, 55.07888], [22.02582, 55.05078], [22.06087, 55.02935], [22.11697, 55.02131], [22.14267, 55.05345], [22.31562, 55.0655], [22.47688, 55.04408], [22.58907, 55.07085], [22.60075, 55.01863], [22.65451, 54.97037], [22.68723, 54.9811], [22.76422, 54.92521], [22.85083, 54.88711], [22.87317, 54.79492], [22.73631, 54.72952], [22.73397, 54.66604], [22.75467, 54.6483], [22.74225, 54.64339], [22.7522, 54.63525], [22.68021, 54.58486], [22.71293, 54.56454], [22.67788, 54.532], [22.70208, 54.45312], [22.7253, 54.41732], [22.79705, 54.36264], [22.83756, 54.40827], [23.00584, 54.38514], [22.99649, 54.35927], [23.05726, 54.34565], [23.04323, 54.31567], [23.104, 54.29794], [23.13905, 54.31567], [23.15526, 54.31076], [23.15938, 54.29894], [23.24656, 54.25701], [23.3494, 54.25155], [23.39525, 54.21672], [23.42418, 54.17911], [23.45223, 54.17775], [23.49196, 54.14764], [23.52702, 54.04622], [23.48261, 53.98855], [23.51284, 53.95052], [23.61677, 53.92691], [23.71726, 53.93379], [23.80543, 53.89558], [23.81309, 53.94205], [23.95098, 53.9613], [23.98837, 53.92554], [24.19638, 53.96405], [24.34128, 53.90076], [24.44411, 53.90076], [24.62275, 54.00217], [24.69652, 54.01901], [24.69185, 53.96543], [24.74279, 53.96663], [24.85311, 54.02862], [24.77131, 54.11091], [24.96894, 54.17589], [24.991, 54.14241], [25.0728, 54.13419], [25.19199, 54.219], [25.22705, 54.26271], [25.35559, 54.26544], [25.509, 54.30267], [25.56823, 54.25212], [25.51452, 54.17799], [25.54724, 54.14925], [25.64875, 54.1259], [25.71084, 54.16704], [25.78563, 54.15747], [25.78553, 54.23327], [25.68513, 54.31727], [25.55425, 54.31591], [25.5376, 54.33158], [25.63371, 54.42075], [25.62203, 54.4656], [25.64813, 54.48704], [25.68045, 54.5321], [25.75977, 54.57252], [25.74122, 54.80108], [25.89462, 54.93438], [25.99129, 54.95705], [26.05907, 54.94631], [26.13386, 54.98924], [26.20397, 54.99729], [26.26941, 55.08032], [26.23202, 55.10439], [26.30628, 55.12536], [26.35121, 55.1525], [26.46249, 55.12814], [26.51481, 55.16051], [26.54753, 55.14181], [26.69243, 55.16718], [26.68075, 55.19787], [26.72983, 55.21788], [26.73017, 55.24226], [26.835, 55.28182], [26.83266, 55.30444], [26.80929, 55.31642], [26.6714, 55.33902], [26.5709, 55.32572], [26.44937, 55.34832], [26.5522, 55.40277], [26.55094, 55.5093], [26.63167, 55.57887], [26.63231, 55.67968], [26.58248, 55.6754], [26.46661, 55.70375], [26.39561, 55.71156], [26.18509, 55.86813], [26.03815, 55.95884], [25.90047, 56.0013], [25.85893, 56.00188], [25.81773, 56.05444], [25.69246, 56.08892], [25.68588, 56.14725], [25.53621, 56.16663], [25.39751, 56.15707], [25.23099, 56.19147], [25.09325, 56.1878], [25.05762, 56.26742], [24.89005, 56.46666]]]]
25955 nameEn: "Luxembourg",
25956 groups: ["EU", "155", "150", "UN"],
25957 callingCodes: ["352"]
25960 type: "MultiPolygon",
25961 coordinates: [[[[6.1379, 50.12964], [6.1137, 50.13668], [6.12028, 50.16374], [6.08577, 50.17246], [6.06406, 50.15344], [6.03093, 50.16362], [6.02488, 50.18283], [5.96453, 50.17259], [5.95929, 50.13295], [5.89488, 50.11476], [5.8857, 50.07824], [5.85474, 50.06342], [5.86904, 50.04614], [5.8551, 50.02683], [5.81866, 50.01286], [5.82331, 49.99662], [5.83968, 49.9892], [5.83467, 49.97823], [5.81163, 49.97142], [5.80833, 49.96451], [5.77291, 49.96056], [5.77314, 49.93646], [5.73621, 49.89796], [5.78415, 49.87922], [5.75269, 49.8711], [5.75861, 49.85631], [5.74567, 49.85368], [5.75884, 49.84811], [5.74953, 49.84709], [5.74975, 49.83933], [5.74076, 49.83823], [5.7404, 49.83452], [5.74844, 49.82435], [5.74364, 49.82058], [5.74953, 49.81428], [5.75409, 49.79239], [5.78871, 49.7962], [5.82245, 49.75048], [5.83149, 49.74729], [5.82562, 49.72395], [5.84193, 49.72161], [5.86503, 49.72739], [5.88677, 49.70951], [5.86527, 49.69291], [5.86175, 49.67862], [5.9069, 49.66377], [5.90164, 49.6511], [5.90599, 49.63853], [5.88552, 49.63507], [5.88393, 49.62802], [5.87609, 49.62047], [5.8762, 49.60898], [5.84826, 49.5969], [5.84971, 49.58674], [5.86986, 49.58756], [5.87256, 49.57539], [5.8424, 49.56082], [5.84692, 49.55663], [5.84143, 49.5533], [5.81838, 49.54777], [5.80871, 49.5425], [5.81664, 49.53775], [5.83648, 49.5425], [5.84466, 49.53027], [5.83467, 49.52717], [5.83389, 49.52152], [5.86571, 49.50015], [5.94128, 49.50034], [5.94224, 49.49608], [5.96876, 49.49053], [5.97693, 49.45513], [6.02648, 49.45451], [6.02743, 49.44845], [6.04176, 49.44801], [6.05553, 49.46663], [6.07887, 49.46399], [6.08373, 49.45594], [6.10072, 49.45268], [6.09845, 49.46351], [6.10325, 49.4707], [6.12346, 49.4735], [6.12814, 49.49365], [6.14321, 49.48796], [6.16115, 49.49297], [6.15366, 49.50226], [6.17386, 49.50934], [6.19543, 49.50536], [6.2409, 49.51408], [6.25029, 49.50609], [6.27875, 49.503], [6.28818, 49.48465], [6.3687, 49.4593], [6.36778, 49.46937], [6.36907, 49.48931], [6.36788, 49.50377], [6.35666, 49.52931], [6.38072, 49.55171], [6.38228, 49.55855], [6.35825, 49.57053], [6.36676, 49.57813], [6.38024, 49.57593], [6.38342, 49.5799], [6.37464, 49.58886], [6.385, 49.59946], [6.39822, 49.60081], [6.41861, 49.61723], [6.4413, 49.65722], [6.43768, 49.66021], [6.42726, 49.66078], [6.42937, 49.66857], [6.44654, 49.67799], [6.46048, 49.69092], [6.48014, 49.69767], [6.49785, 49.71118], [6.50647, 49.71353], [6.5042, 49.71808], [6.49694, 49.72205], [6.49535, 49.72645], [6.50261, 49.72718], [6.51397, 49.72058], [6.51805, 49.72425], [6.50193, 49.73291], [6.50174, 49.75292], [6.51646, 49.75961], [6.51828, 49.76855], [6.51056, 49.77515], [6.51669, 49.78336], [6.50534, 49.78952], [6.52169, 49.79787], [6.53122, 49.80666], [6.52121, 49.81338], [6.51215, 49.80124], [6.50647, 49.80916], [6.48718, 49.81267], [6.47111, 49.82263], [6.45425, 49.81164], [6.44131, 49.81443], [6.42905, 49.81091], [6.42521, 49.81591], [6.40022, 49.82029], [6.36576, 49.85032], [6.34267, 49.84974], [6.33585, 49.83785], [6.32098, 49.83728], [6.32303, 49.85133], [6.30963, 49.87021], [6.29692, 49.86685], [6.28874, 49.87592], [6.26146, 49.88203], [6.23496, 49.89972], [6.22926, 49.92096], [6.21882, 49.92403], [6.22608, 49.929], [6.22094, 49.94955], [6.19856, 49.95053], [6.19089, 49.96991], [6.18045, 49.96611], [6.18554, 49.95622], [6.17872, 49.9537], [6.16466, 49.97086], [6.1701, 49.98518], [6.14147, 49.99563], [6.14948, 50.00908], [6.13806, 50.01056], [6.1295, 50.01849], [6.13273, 50.02019], [6.13794, 50.01466], [6.14666, 50.02207], [6.13044, 50.02929], [6.13458, 50.04141], [6.11274, 50.05916], [6.12055, 50.09171], [6.1379, 50.12964]]]]
25971 groups: ["EU", "154", "150", "UN"],
25972 callingCodes: ["371"]
25975 type: "MultiPolygon",
25976 coordinates: [[[[27.34698, 57.52242], [26.90364, 57.62823], [26.54675, 57.51813], [26.46527, 57.56885], [26.29253, 57.59244], [26.1866, 57.6849], [26.2029, 57.7206], [26.08098, 57.76619], [26.0543, 57.76105], [26.03332, 57.7718], [26.02415, 57.76865], [26.02069, 57.77169], [26.0266, 57.77441], [26.027, 57.78158], [26.02456, 57.78342], [26.0324, 57.79037], [26.05949, 57.84744], [25.73499, 57.90193], [25.29581, 58.08288], [25.28237, 57.98539], [25.19484, 58.0831], [24.3579, 57.87471], [24.26221, 57.91787], [23.20055, 57.56697], [22.80496, 57.87798], [19.84909, 57.57876], [19.64795, 57.06466], [20.68447, 56.04073], [21.15016, 56.07818], [21.24644, 56.16917], [21.49736, 56.29106], [21.57888, 56.31406], [21.74558, 56.33181], [22.00548, 56.41508], [22.09728, 56.42851], [22.3361, 56.4016], [22.56441, 56.39305], [22.69354, 56.36284], [22.83048, 56.367], [22.96988, 56.41213], [23.09531, 56.30511], [23.17312, 56.36795], [23.31606, 56.3827], [23.40486, 56.37689], [23.49803, 56.34307], [23.75726, 56.37282], [24.02657, 56.3231], [24.13139, 56.24881], [24.32334, 56.30226], [24.42746, 56.26522], [24.58143, 56.29125], [24.57353, 56.31525], [24.70022, 56.40483], [24.83686, 56.41565], [24.89005, 56.46666], [25.05762, 56.26742], [25.09325, 56.1878], [25.23099, 56.19147], [25.39751, 56.15707], [25.53621, 56.16663], [25.68588, 56.14725], [25.69246, 56.08892], [25.81773, 56.05444], [25.85893, 56.00188], [25.90047, 56.0013], [26.03815, 55.95884], [26.18509, 55.86813], [26.39561, 55.71156], [26.46661, 55.70375], [26.58248, 55.6754], [26.63231, 55.67968], [26.64888, 55.70515], [26.71802, 55.70645], [26.76872, 55.67658], [26.87448, 55.7172], [26.97153, 55.8102], [27.1559, 55.85032], [27.27804, 55.78299], [27.3541, 55.8089], [27.61683, 55.78558], [27.63065, 55.89687], [27.97865, 56.11849], [28.15217, 56.16964], [28.23716, 56.27588], [28.16599, 56.37806], [28.19057, 56.44637], [28.10069, 56.524], [28.13526, 56.57989], [28.04768, 56.59004], [27.86101, 56.88204], [27.66511, 56.83921], [27.86101, 57.29402], [27.52453, 57.42826], [27.56832, 57.53728], [27.34698, 57.52242]]]]
25986 groups: ["015", "002", "UN"],
25987 callingCodes: ["218"]
25990 type: "MultiPolygon",
25991 coordinates: [[[[26.92891, 33.39516], [11.58941, 33.36891], [11.55852, 33.1409], [11.51549, 33.09826], [11.46037, 32.6307], [11.57828, 32.48013], [11.53898, 32.4138], [11.04234, 32.2145], [10.7315, 31.97235], [10.62788, 31.96629], [10.48497, 31.72956], [10.31364, 31.72648], [10.12239, 31.42098], [10.29516, 30.90337], [9.88152, 30.34074], [9.76848, 30.34366], [9.55544, 30.23971], [9.3876, 30.16738], [9.78136, 29.40961], [9.89569, 26.57696], [9.51696, 26.39148], [9.38834, 26.19288], [10.03146, 25.35635], [10.02432, 24.98124], [10.33159, 24.5465], [10.85323, 24.5595], [11.41061, 24.21456], [11.62498, 24.26669], [11.96886, 23.51735], [13.5631, 23.16574], [14.22918, 22.61719], [14.99751, 23.00539], [15.99566, 23.49639], [23.99539, 19.49944], [23.99715, 20.00038], [24.99794, 19.99661], [24.99885, 21.99535], [24.99968, 29.24574], [24.71117, 30.17441], [25.01077, 30.73861], [24.8458, 31.39877], [26.92891, 33.39516]]]]
26001 groups: ["015", "002", "UN"],
26002 callingCodes: ["212"]
26005 type: "MultiPolygon",
26006 coordinates: [[[[-2.27707, 35.35051], [-5.10878, 36.05227], [-7.2725, 35.73269], [-14.43883, 27.02969], [-17.27295, 21.93519], [-17.21511, 21.34226], [-17.02707, 21.34022], [-16.9978, 21.36239], [-16.44269, 21.39745], [-14.78487, 21.36587], [-14.47329, 21.63839], [-14.48112, 22.00886], [-14.1291, 22.41636], [-14.10361, 22.75501], [-13.75627, 23.77231], [-13.00628, 24.01923], [-12.92147, 24.39502], [-12.12281, 25.13682], [-12.06001, 26.04442], [-11.62052, 26.05229], [-11.38635, 26.611], [-11.23622, 26.72023], [-11.35695, 26.8505], [-10.68417, 26.90984], [-9.81998, 26.71379], [-9.56957, 26.90042], [-9.08698, 26.98639], [-8.71787, 26.9898], [-8.77527, 27.66663], [-8.66879, 27.6666], [-8.6715, 28.71194], [-7.61585, 29.36252], [-6.95824, 29.50924], [-6.78351, 29.44634], [-6.69965, 29.51623], [-5.75616, 29.61407], [-5.72121, 29.52322], [-5.58831, 29.48103], [-5.21671, 29.95253], [-4.6058, 30.28343], [-4.31774, 30.53229], [-3.64735, 30.67539], [-3.65418, 30.85566], [-3.54944, 31.0503], [-3.77103, 31.14984], [-3.77647, 31.31912], [-3.66386, 31.39202], [-3.66314, 31.6339], [-2.82784, 31.79459], [-2.93873, 32.06557], [-2.46166, 32.16603], [-1.22829, 32.07832], [-1.15735, 32.12096], [-1.24453, 32.1917], [-1.24998, 32.32993], [-0.9912, 32.52467], [-1.37794, 32.73628], [-1.54244, 32.95499], [-1.46249, 33.0499], [-1.67067, 33.27084], [-1.59508, 33.59929], [-1.73494, 33.71721], [-1.64666, 34.10405], [-1.78042, 34.39018], [-1.69788, 34.48056], [-1.84569, 34.61907], [-1.73707, 34.74226], [-1.97469, 34.886], [-1.97833, 34.93218], [-2.04734, 34.93218], [-2.21445, 35.04378], [-2.21248, 35.08532], [-2.27707, 35.35051]], [[-2.91909, 35.33927], [-2.92272, 35.27509], [-2.93893, 35.26737], [-2.95065, 35.26576], [-2.95431, 35.2728], [-2.96516, 35.27967], [-2.96826, 35.28296], [-2.96507, 35.28801], [-2.97035, 35.28852], [-2.96978, 35.29459], [-2.96648, 35.30475], [-2.96038, 35.31609], [-2.91909, 35.33927]], [[-3.90602, 35.21494], [-3.89343, 35.22728], [-3.88372, 35.20767], [-3.90602, 35.21494]], [[-4.30191, 35.17419], [-4.29436, 35.17149], [-4.30112, 35.17058], [-4.30191, 35.17419]], [[-2.40316, 35.16893], [-2.45965, 35.16527], [-2.43262, 35.20652], [-2.40316, 35.16893]], [[-5.38491, 35.92591], [-5.21179, 35.90091], [-5.34379, 35.8711], [-5.35844, 35.87375], [-5.37338, 35.88417], [-5.38491, 35.92591]]]]
26016 groups: ["155", "150", "UN"],
26017 callingCodes: ["377"]
26020 type: "MultiPolygon",
26021 coordinates: [[[[7.47823, 43.73341], [7.4379, 43.74963], [7.4389, 43.75151], [7.43708, 43.75197], [7.43624, 43.75014], [7.43013, 43.74895], [7.42809, 43.74396], [7.42443, 43.74087], [7.42299, 43.74176], [7.42062, 43.73977], [7.41233, 43.73439], [7.41298, 43.73311], [7.41291, 43.73168], [7.41113, 43.73156], [7.40903, 43.7296], [7.42422, 43.72209], [7.47823, 43.73341]]]]
26031 groups: ["151", "150", "UN"],
26032 callingCodes: ["373"]
26035 type: "MultiPolygon",
26036 coordinates: [[[[27.74422, 48.45926], [27.6658, 48.44034], [27.59027, 48.46311], [27.5889, 48.49224], [27.46942, 48.454], [27.44333, 48.41209], [27.37741, 48.41026], [27.37604, 48.44398], [27.32159, 48.4434], [27.27855, 48.37534], [27.13434, 48.37288], [27.08078, 48.43214], [27.0231, 48.42485], [27.03821, 48.37653], [26.93384, 48.36558], [26.85556, 48.41095], [26.71274, 48.40388], [26.82809, 48.31629], [26.79239, 48.29071], [26.6839, 48.35828], [26.62823, 48.25804], [26.81161, 48.25049], [26.87708, 48.19919], [26.94265, 48.1969], [26.98042, 48.15752], [26.96119, 48.13003], [27.04118, 48.12522], [27.02985, 48.09083], [27.15622, 47.98538], [27.1618, 47.92391], [27.29069, 47.73722], [27.25519, 47.71366], [27.32202, 47.64009], [27.3979, 47.59473], [27.47942, 47.48113], [27.55731, 47.46637], [27.60263, 47.32507], [27.68706, 47.28962], [27.73172, 47.29248], [27.81892, 47.1381], [28.09095, 46.97621], [28.12173, 46.82283], [28.24808, 46.64305], [28.22281, 46.50481], [28.25769, 46.43334], [28.18902, 46.35283], [28.19864, 46.31869], [28.10937, 46.22852], [28.13684, 46.18099], [28.08612, 46.01105], [28.13111, 45.92819], [28.16568, 45.6421], [28.08927, 45.6051], [28.18741, 45.47358], [28.21139, 45.46895], [28.30201, 45.54744], [28.41836, 45.51715], [28.43072, 45.48538], [28.51449, 45.49982], [28.49252, 45.56716], [28.54196, 45.58062], [28.51587, 45.6613], [28.47879, 45.66994], [28.52823, 45.73803], [28.70401, 45.78019], [28.69852, 45.81753], [28.78503, 45.83475], [28.74383, 45.96664], [28.98004, 46.00385], [29.00613, 46.04962], [28.94643, 46.09176], [29.06656, 46.19716], [28.94953, 46.25852], [28.98478, 46.31803], [29.004, 46.31495], [28.9306, 46.45699], [29.01241, 46.46177], [29.02409, 46.49582], [29.23547, 46.55435], [29.24886, 46.37912], [29.35357, 46.49505], [29.49914, 46.45889], [29.5939, 46.35472], [29.6763, 46.36041], [29.66359, 46.4215], [29.74496, 46.45605], [29.88329, 46.35851], [29.94114, 46.40114], [30.09103, 46.38694], [30.16794, 46.40967], [30.02511, 46.45132], [29.88916, 46.54302], [29.94409, 46.56002], [29.9743, 46.75325], [29.94522, 46.80055], [29.98814, 46.82358], [29.87405, 46.88199], [29.75458, 46.8604], [29.72986, 46.92234], [29.57056, 46.94766], [29.62137, 47.05069], [29.61038, 47.09932], [29.53044, 47.07851], [29.49732, 47.12878], [29.57696, 47.13581], [29.54996, 47.24962], [29.59665, 47.25521], [29.5733, 47.36508], [29.48678, 47.36043], [29.47854, 47.30366], [29.39889, 47.30179], [29.3261, 47.44664], [29.18603, 47.43387], [29.11743, 47.55001], [29.22414, 47.60012], [29.22242, 47.73607], [29.27255, 47.79953], [29.20663, 47.80367], [29.27804, 47.88893], [29.19839, 47.89261], [29.1723, 47.99013], [28.9306, 47.96255], [28.8414, 48.03392], [28.85232, 48.12506], [28.69896, 48.13106], [28.53921, 48.17453], [28.48428, 48.0737], [28.42454, 48.12047], [28.43701, 48.15832], [28.38712, 48.17567], [28.34009, 48.13147], [28.30609, 48.14018], [28.30586, 48.1597], [28.34912, 48.1787], [28.36996, 48.20543], [28.35519, 48.24957], [28.32508, 48.23384], [28.2856, 48.23202], [28.19314, 48.20749], [28.17666, 48.25963], [28.07504, 48.23494], [28.09873, 48.3124], [28.04527, 48.32661], [27.95883, 48.32368], [27.88391, 48.36699], [27.87533, 48.4037], [27.81902, 48.41874], [27.79225, 48.44244], [27.74422, 48.45926]]]]
26045 nameEn: "Montenegro",
26046 groups: ["039", "150", "UN"],
26047 callingCodes: ["382"]
26050 type: "MultiPolygon",
26051 coordinates: [[[[19.22807, 43.5264], [19.15685, 43.53943], [19.13933, 43.5282], [19.04934, 43.50384], [19.01078, 43.55806], [18.91379, 43.50299], [18.95469, 43.49367], [18.96053, 43.45042], [19.01078, 43.43854], [19.04071, 43.397], [19.08673, 43.31453], [19.08206, 43.29668], [19.04233, 43.30008], [19.00844, 43.24988], [18.95001, 43.29327], [18.95819, 43.32899], [18.90911, 43.36383], [18.83912, 43.34795], [18.84794, 43.33735], [18.85342, 43.32426], [18.76538, 43.29838], [18.6976, 43.25243], [18.71747, 43.2286], [18.66605, 43.2056], [18.64735, 43.14766], [18.66254, 43.03928], [18.52232, 43.01451], [18.49076, 42.95553], [18.49661, 42.89306], [18.4935, 42.86433], [18.47633, 42.85829], [18.45921, 42.81682], [18.47324, 42.74992], [18.56789, 42.72074], [18.55221, 42.69045], [18.54603, 42.69171], [18.54841, 42.68328], [18.57373, 42.64429], [18.52232, 42.62279], [18.55504, 42.58409], [18.53751, 42.57376], [18.49778, 42.58409], [18.43735, 42.55921], [18.44307, 42.51077], [18.43588, 42.48556], [18.52152, 42.42302], [18.54128, 42.39171], [18.45131, 42.21682], [19.26406, 41.74971], [19.37597, 41.84849], [19.37451, 41.8842], [19.33812, 41.90669], [19.34601, 41.95675], [19.37691, 41.96977], [19.36867, 42.02564], [19.37548, 42.06835], [19.40687, 42.10024], [19.28623, 42.17745], [19.42, 42.33019], [19.42352, 42.36546], [19.4836, 42.40831], [19.65972, 42.62774], [19.73244, 42.66299], [19.77375, 42.58517], [19.74731, 42.57422], [19.76549, 42.50237], [19.82333, 42.46581], [19.9324, 42.51699], [20.00842, 42.5109], [20.01834, 42.54622], [20.07761, 42.55582], [20.0969, 42.65559], [20.02915, 42.71147], [20.02088, 42.74789], [20.04898, 42.77701], [20.2539, 42.76245], [20.27869, 42.81945], [20.35692, 42.8335], [20.34528, 42.90676], [20.16415, 42.97177], [20.14896, 42.99058], [20.12325, 42.96237], [20.05431, 42.99571], [20.04729, 43.02732], [19.98887, 43.0538], [19.96549, 43.11098], [19.92576, 43.08539], [19.79255, 43.11951], [19.76918, 43.16044], [19.64063, 43.19027], [19.62661, 43.2286], [19.54598, 43.25158], [19.52962, 43.31623], [19.48171, 43.32644], [19.44315, 43.38846], [19.22229, 43.47926], [19.22807, 43.5264]]]]
26059 wikidata: "Q126125",
26060 nameEn: "Saint-Martin",
26062 groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
26063 callingCodes: ["590"]
26066 type: "MultiPolygon",
26067 coordinates: [[[[-62.93924, 18.02904], [-62.62718, 18.26185], [-63.35989, 18.06012], [-63.33064, 17.9615], [-63.13502, 18.05445], [-63.11042, 18.05339], [-63.09686, 18.04608], [-63.07759, 18.04943], [-63.0579, 18.06614], [-63.04039, 18.05619], [-63.02323, 18.05757], [-62.93924, 18.02904]]]]
26076 nameEn: "Madagascar",
26078 groups: ["014", "202", "002", "UN"],
26079 callingCodes: ["261"]
26082 type: "MultiPolygon",
26083 coordinates: [[[[51.93891, -10.85085], [45.84651, -12.77177], [42.14681, -19.63341], [45.80092, -33.00974], [51.93891, -10.85085]]]]
26092 nameEn: "Marshall Islands",
26093 groups: ["057", "009", "UN"],
26094 roadSpeedUnit: "mph",
26095 callingCodes: ["692"]
26098 type: "MultiPolygon",
26099 coordinates: [[[[169, 3.9], [173.53711, 5.70687], [169.29099, 15.77133], [159.04653, 10.59067], [169, 3.9]]]]
26108 nameEn: "North Macedonia",
26109 groups: ["039", "150", "UN"],
26110 callingCodes: ["389"]
26113 type: "MultiPolygon",
26114 coordinates: [[[[22.34773, 42.31725], [22.29275, 42.34913], [22.29605, 42.37477], [22.16384, 42.32103], [22.02908, 42.29848], [21.94405, 42.34669], [21.91595, 42.30392], [21.84654, 42.3247], [21.77176, 42.2648], [21.70111, 42.23789], [21.58992, 42.25915], [21.52145, 42.24465], [21.50823, 42.27156], [21.43882, 42.2789], [21.43882, 42.23609], [21.38428, 42.24465], [21.30496, 42.1418], [21.29913, 42.13954], [21.31983, 42.10993], [21.22728, 42.08909], [21.16614, 42.19815], [21.11491, 42.20794], [20.75464, 42.05229], [20.76786, 41.91839], [20.68523, 41.85318], [20.59524, 41.8818], [20.55976, 41.87068], [20.57144, 41.7897], [20.53405, 41.78099], [20.51301, 41.72433], [20.52937, 41.69292], [20.51769, 41.65975], [20.55508, 41.58113], [20.52103, 41.56473], [20.45809, 41.5549], [20.45331, 41.51436], [20.49039, 41.49277], [20.51301, 41.442], [20.55976, 41.4087], [20.52119, 41.34381], [20.49432, 41.33679], [20.51068, 41.2323], [20.59715, 41.13644], [20.58546, 41.11179], [20.59832, 41.09066], [20.63454, 41.0889], [20.65558, 41.08009], [20.71634, 40.91781], [20.73504, 40.9081], [20.81567, 40.89662], [20.83671, 40.92752], [20.94305, 40.92399], [20.97693, 40.90103], [20.97887, 40.85475], [21.15262, 40.85546], [21.21105, 40.8855], [21.25779, 40.86165], [21.35595, 40.87578], [21.41555, 40.9173], [21.53007, 40.90759], [21.57448, 40.86076], [21.69601, 40.9429], [21.7556, 40.92525], [21.91102, 41.04786], [21.90869, 41.09191], [22.06527, 41.15617], [22.1424, 41.12449], [22.17629, 41.15969], [22.26744, 41.16409], [22.42285, 41.11921], [22.5549, 41.13065], [22.58295, 41.11568], [22.62852, 41.14385], [22.65306, 41.18168], [22.71266, 41.13945], [22.74538, 41.16321], [22.76408, 41.32225], [22.81199, 41.3398], [22.93334, 41.34104], [22.96331, 41.35782], [22.95513, 41.63265], [23.03342, 41.71034], [23.01239, 41.76527], [22.96682, 41.77137], [22.90254, 41.87587], [22.86749, 42.02275], [22.67701, 42.06614], [22.51224, 42.15457], [22.50289, 42.19527], [22.47251, 42.20393], [22.38136, 42.30339], [22.34773, 42.31725]]]]
26124 groups: ["011", "202", "002", "UN"],
26125 callingCodes: ["223"]
26128 type: "MultiPolygon",
26129 coordinates: [[[[-4.83423, 24.99935], [-6.57191, 25.0002], [-5.60725, 16.49919], [-5.33435, 16.33354], [-5.50165, 15.50061], [-9.32979, 15.50032], [-9.31106, 15.69412], [-9.33314, 15.7044], [-9.44673, 15.60553], [-9.40447, 15.4396], [-10.71721, 15.4223], [-10.90932, 15.11001], [-11.43483, 15.62339], [-11.70705, 15.51558], [-11.94903, 14.76143], [-12.23936, 14.76324], [-11.93043, 13.84505], [-12.06897, 13.71049], [-11.83345, 13.33333], [-11.63025, 13.39174], [-11.39935, 12.97808], [-11.37536, 12.40788], [-11.50006, 12.17826], [-11.24136, 12.01286], [-10.99758, 12.24634], [-10.80355, 12.1053], [-10.71897, 11.91552], [-10.30604, 12.24634], [-9.714, 12.0226], [-9.63938, 12.18312], [-9.32097, 12.29009], [-9.38067, 12.48446], [-9.13689, 12.50875], [-8.94784, 12.34842], [-8.80854, 11.66715], [-8.40058, 11.37466], [-8.66923, 10.99397], [-8.35083, 11.06234], [-8.2667, 10.91762], [-8.32614, 10.69273], [-8.22711, 10.41722], [-8.10207, 10.44649], [-7.9578, 10.2703], [-7.97971, 10.17117], [-7.92107, 10.15577], [-7.63048, 10.46334], [-7.54462, 10.40921], [-7.52261, 10.4655], [-7.44555, 10.44602], [-7.3707, 10.24677], [-7.13331, 10.24877], [-7.0603, 10.14711], [-7.00966, 10.15794], [-6.97444, 10.21644], [-7.01186, 10.25111], [-6.93921, 10.35291], [-6.68164, 10.35074], [-6.63541, 10.66893], [-6.52974, 10.59104], [-6.42847, 10.5694], [-6.40646, 10.69922], [-6.325, 10.68624], [-6.24795, 10.74248], [-6.1731, 10.46983], [-6.18851, 10.24244], [-5.99478, 10.19694], [-5.78124, 10.43952], [-5.65135, 10.46767], [-5.51058, 10.43177], [-5.46643, 10.56074], [-5.47083, 10.75329], [-5.41579, 10.84628], [-5.49284, 11.07538], [-5.32994, 11.13371], [-5.32553, 11.21578], [-5.25949, 11.24816], [-5.25509, 11.36905], [-5.20665, 11.43811], [-5.22867, 11.60421], [-5.29251, 11.61715], [-5.26389, 11.75728], [-5.40258, 11.8327], [-5.26389, 11.84778], [-5.07897, 11.97918], [-4.72893, 12.01579], [-4.70692, 12.06746], [-4.62987, 12.06531], [-4.62546, 12.13204], [-4.54841, 12.1385], [-4.57703, 12.19875], [-4.41412, 12.31922], [-4.47356, 12.71252], [-4.238, 12.71467], [-4.21819, 12.95722], [-4.34477, 13.12927], [-3.96501, 13.49778], [-3.90558, 13.44375], [-3.96282, 13.38164], [-3.7911, 13.36665], [-3.54454, 13.1781], [-3.4313, 13.1588], [-3.43507, 13.27272], [-3.23599, 13.29035], [-3.28396, 13.5422], [-3.26407, 13.70699], [-2.88189, 13.64921], [-2.90831, 13.81174], [-2.84667, 14.05532], [-2.66175, 14.14713], [-2.47587, 14.29671], [-2.10223, 14.14878], [-1.9992, 14.19011], [-1.97945, 14.47709], [-1.68083, 14.50023], [-1.32166, 14.72774], [-1.05875, 14.7921], [-0.72004, 15.08655], [-0.24673, 15.07805], [0.06588, 14.96961], [0.23859, 15.00135], [0.72632, 14.95898], [0.96711, 14.98275], [1.31275, 15.27978], [3.01806, 15.34571], [3.03134, 15.42221], [3.50368, 15.35934], [4.19893, 16.39923], [4.21787, 17.00118], [4.26762, 17.00432], [4.26651, 19.14224], [3.36082, 18.9745], [3.12501, 19.1366], [3.24648, 19.81703], [1.20992, 20.73533], [1.15698, 21.12843], [-4.83423, 24.99935]]]]
26139 aliases: ["Burma", "BU"],
26140 groups: ["035", "142", "UN"],
26141 callingCodes: ["95"]
26144 type: "MultiPolygon",
26145 coordinates: [[[[92.62187, 21.87037], [92.59775, 21.6092], [92.68152, 21.28454], [92.60187, 21.24615], [92.55105, 21.3856], [92.43158, 21.37025], [92.37939, 21.47764], [92.20087, 21.337], [92.17752, 21.17445], [92.26071, 21.05697], [92.47409, 20.38654], [92.61042, 13.76986], [94.6371, 13.81803], [97.63455, 9.60854], [98.12555, 9.44056], [98.33094, 9.91973], [98.47298, 9.95782], [98.52291, 9.92389], [98.55174, 9.92804], [98.7391, 10.31488], [98.81944, 10.52761], [98.77275, 10.62548], [98.78511, 10.68351], [98.86819, 10.78336], [99.0069, 10.85485], [98.99701, 10.92962], [99.02337, 10.97217], [99.06938, 10.94857], [99.32756, 11.28545], [99.31573, 11.32081], [99.39485, 11.3925], [99.47598, 11.62434], [99.5672, 11.62732], [99.64108, 11.78948], [99.64891, 11.82699], [99.53424, 12.02317], [99.56445, 12.14805], [99.47519, 12.1353], [99.409, 12.60603], [99.29254, 12.68921], [99.18905, 12.84799], [99.18748, 12.9898], [99.10646, 13.05804], [99.12225, 13.19847], [99.20617, 13.20575], [99.16695, 13.72621], [98.97356, 14.04868], [98.56762, 14.37701], [98.24874, 14.83013], [98.18821, 15.13125], [98.22, 15.21327], [98.30446, 15.30667], [98.40522, 15.25268], [98.41906, 15.27103], [98.39351, 15.34177], [98.4866, 15.39154], [98.56027, 15.33471], [98.58598, 15.46821], [98.541, 15.65406], [98.59853, 15.87197], [98.57019, 16.04578], [98.69585, 16.13353], [98.8376, 16.11706], [98.92656, 16.36425], [98.84485, 16.42354], [98.68074, 16.27068], [98.63817, 16.47424], [98.57912, 16.55983], [98.5695, 16.62826], [98.51113, 16.64503], [98.51833, 16.676], [98.51472, 16.68521], [98.51579, 16.69433], [98.51043, 16.70107], [98.49713, 16.69022], [98.50253, 16.7139], [98.46994, 16.73613], [98.53833, 16.81934], [98.49603, 16.8446], [98.52624, 16.89979], [98.39441, 17.06266], [98.34566, 17.04822], [98.10439, 17.33847], [98.11185, 17.36829], [97.91829, 17.54504], [97.76407, 17.71595], [97.66794, 17.88005], [97.73723, 17.97912], [97.60841, 18.23846], [97.64116, 18.29778], [97.56219, 18.33885], [97.50383, 18.26844], [97.34522, 18.54596], [97.36444, 18.57138], [97.5258, 18.4939], [97.76752, 18.58097], [97.73836, 18.88478], [97.66487, 18.9371], [97.73654, 18.9812], [97.73797, 19.04261], [97.83479, 19.09972], [97.84024, 19.22217], [97.78606, 19.26769], [97.84186, 19.29526], [97.78769, 19.39429], [97.88423, 19.5041], [97.84715, 19.55782], [98.04364, 19.65755], [98.03314, 19.80941], [98.13829, 19.78541], [98.24884, 19.67876], [98.51182, 19.71303], [98.56065, 19.67807], [98.83661, 19.80931], [98.98679, 19.7419], [99.0735, 20.10298], [99.20328, 20.12877], [99.416, 20.08614], [99.52943, 20.14811], [99.5569, 20.20676], [99.46077, 20.36198], [99.46008, 20.39673], [99.68255, 20.32077], [99.81096, 20.33687], [99.86383, 20.44371], [99.88211, 20.44488], [99.88451, 20.44596], [99.89168, 20.44548], [99.89301, 20.44311], [99.89692, 20.44789], [99.90499, 20.4487], [99.91616, 20.44986], [99.95721, 20.46301], [100.08404, 20.36626], [100.1957, 20.68247], [100.36375, 20.82783], [100.51079, 20.82194], [100.60112, 20.8347], [100.64628, 20.88279], [100.50974, 20.88574], [100.55281, 21.02796], [100.63578, 21.05639], [100.72716, 21.31786], [100.80173, 21.2934], [101.00234, 21.39612], [101.16198, 21.52808], [101.15156, 21.56129], [101.11744, 21.77659], [100.87265, 21.67396], [100.72143, 21.51898], [100.57861, 21.45637], [100.4811, 21.46148], [100.42892, 21.54325], [100.35201, 21.53176], [100.25863, 21.47043], [100.18447, 21.51898], [100.1625, 21.48704], [100.12542, 21.50365], [100.10757, 21.59945], [100.17486, 21.65306], [100.12679, 21.70539], [100.04956, 21.66843], [99.98654, 21.71064], [99.94003, 21.82782], [99.99084, 21.97053], [99.96612, 22.05965], [99.85351, 22.04183], [99.47585, 22.13345], [99.33166, 22.09656], [99.1552, 22.15874], [99.19176, 22.16983], [99.17318, 22.18025], [99.28771, 22.4105], [99.37972, 22.50188], [99.38247, 22.57544], [99.31243, 22.73893], [99.45654, 22.85726], [99.43537, 22.94086], [99.54218, 22.90014], [99.52214, 23.08218], [99.34127, 23.13099], [99.25741, 23.09025], [99.04601, 23.12215], [99.05975, 23.16382], [98.88597, 23.18656], [98.92515, 23.29535], [98.93958, 23.31414], [98.87573, 23.33038], [98.92104, 23.36946], [98.87683, 23.48995], [98.82877, 23.47908], [98.80294, 23.5345], [98.88396, 23.59555], [98.81775, 23.694], [98.82933, 23.72921], [98.79607, 23.77947], [98.68209, 23.80492], [98.67797, 23.9644], [98.89632, 24.10612], [98.87998, 24.15624], [98.85319, 24.13042], [98.59256, 24.08371], [98.54476, 24.13119], [98.20666, 24.11406], [98.07806, 24.07988], [98.06703, 24.08028], [98.0607, 24.07812], [98.05671, 24.07961], [98.05302, 24.07408], [98.04709, 24.07616], [97.99583, 24.04932], [97.98691, 24.03897], [97.93951, 24.01953], [97.90998, 24.02094], [97.88616, 24.00463], [97.88414, 23.99405], [97.88814, 23.98605], [97.89683, 23.98389], [97.89676, 23.97931], [97.8955, 23.97758], [97.88811, 23.97446], [97.86545, 23.97723], [97.84328, 23.97603], [97.79416, 23.95663], [97.79456, 23.94836], [97.72302, 23.89288], [97.64667, 23.84574], [97.5247, 23.94032], [97.62363, 24.00506], [97.72903, 24.12606], [97.75305, 24.16902], [97.72799, 24.18883], [97.72998, 24.2302], [97.76799, 24.26365], [97.71941, 24.29652], [97.66723, 24.30027], [97.65624, 24.33781], [97.7098, 24.35658], [97.66998, 24.45288], [97.60029, 24.4401], [97.52757, 24.43748], [97.56286, 24.54535], [97.56525, 24.72838], [97.54675, 24.74202], [97.5542, 24.74943], [97.56383, 24.75535], [97.56648, 24.76475], [97.64354, 24.79171], [97.70181, 24.84557], [97.73127, 24.83015], [97.76481, 24.8289], [97.79949, 24.85655], [97.72903, 24.91332], [97.72216, 25.08508], [97.77023, 25.11492], [97.83614, 25.2715], [97.92541, 25.20815], [98.14925, 25.41547], [98.12591, 25.50722], [98.18084, 25.56298], [98.16848, 25.62739], [98.25774, 25.6051], [98.31268, 25.55307], [98.40606, 25.61129], [98.54064, 25.85129], [98.63128, 25.79937], [98.70818, 25.86241], [98.60763, 26.01512], [98.57085, 26.11547], [98.63128, 26.15492], [98.66884, 26.09165], [98.7329, 26.17218], [98.67797, 26.24487], [98.72741, 26.36183], [98.77547, 26.61994], [98.7333, 26.85615], [98.69582, 27.56499], [98.43353, 27.67086], [98.42529, 27.55404], [98.32641, 27.51385], [98.13964, 27.9478], [98.15337, 28.12114], [97.90069, 28.3776], [97.79632, 28.33168], [97.70705, 28.5056], [97.56835, 28.55628], [97.50518, 28.49716], [97.47085, 28.2688], [97.41729, 28.29783], [97.34547, 28.21385], [97.31292, 28.06784], [97.35412, 28.06663], [97.38845, 28.01329], [97.35824, 27.87256], [97.29919, 27.92233], [96.90112, 27.62149], [96.91431, 27.45752], [97.17422, 27.14052], [97.14675, 27.09041], [96.89132, 27.17474], [96.85287, 27.2065], [96.88445, 27.25046], [96.73888, 27.36638], [96.55761, 27.29928], [96.40779, 27.29818], [96.15591, 27.24572], [96.04949, 27.19428], [95.93002, 27.04149], [95.81603, 27.01335], [95.437, 26.7083], [95.30339, 26.65372], [95.23513, 26.68499], [95.05798, 26.45408], [95.12801, 26.38397], [95.11428, 26.1019], [95.18556, 26.07338], [94.80117, 25.49359], [94.68032, 25.47003], [94.57458, 25.20318], [94.74212, 25.13606], [94.73937, 25.00545], [94.60204, 24.70889], [94.5526, 24.70764], [94.50729, 24.59281], [94.45279, 24.56656], [94.32362, 24.27692], [94.30215, 24.23752], [94.14081, 23.83333], [93.92089, 23.95812], [93.80279, 23.92549], [93.75952, 24.0003], [93.62871, 24.00922], [93.50616, 23.94432], [93.46633, 23.97067], [93.41415, 24.07854], [93.34735, 24.10151], [93.32351, 24.04468], [93.36059, 23.93176], [93.3908, 23.92925], [93.3908, 23.7622], [93.43475, 23.68299], [93.38805, 23.4728], [93.39981, 23.38828], [93.38781, 23.36139], [93.36862, 23.35426], [93.38478, 23.13698], [93.2878, 23.00464], [93.12988, 23.05772], [93.134, 22.92498], [93.09417, 22.69459], [93.134, 22.59573], [93.11477, 22.54374], [93.13537, 22.45873], [93.18206, 22.43716], [93.19991, 22.25425], [93.14224, 22.24535], [93.15734, 22.18687], [93.04885, 22.20595], [92.99255, 22.05965], [92.99804, 21.98964], [92.93899, 22.02656], [92.89504, 21.95143], [92.86208, 22.05456], [92.70416, 22.16017], [92.67532, 22.03547], [92.60949, 21.97638], [92.62187, 21.87037]]]]
26154 nameEn: "Mongolia",
26155 groups: ["030", "142", "UN"],
26156 callingCodes: ["976"]
26159 type: "MultiPolygon",
26160 coordinates: [[[[102.14032, 51.35566], [101.5044, 51.50467], [101.39085, 51.45753], [100.61116, 51.73028], [99.89203, 51.74903], [99.75578, 51.90108], [99.27888, 51.96876], [98.87768, 52.14563], [98.74142, 51.8637], [98.33222, 51.71832], [98.22053, 51.46579], [98.05257, 51.46696], [97.83305, 51.00248], [98.01472, 50.86652], [97.9693, 50.78044], [98.06393, 50.61262], [98.31373, 50.4996], [98.29481, 50.33561], [97.85197, 49.91339], [97.76871, 49.99861], [97.56432, 49.92801], [97.56811, 49.84265], [97.24639, 49.74737], [96.97388, 49.88413], [95.80056, 50.04239], [95.74757, 49.97915], [95.02465, 49.96941], [94.97166, 50.04725], [94.6121, 50.04239], [94.49477, 50.17832], [94.39258, 50.22193], [94.30823, 50.57498], [92.99595, 50.63183], [93.01109, 50.79001], [92.44714, 50.78762], [92.07173, 50.69585], [91.86048, 50.73734], [89.59711, 49.90851], [89.70687, 49.72535], [88.82499, 49.44808], [88.42449, 49.48821], [88.17223, 49.46934], [88.15543, 49.30314], [87.98977, 49.18147], [87.81333, 49.17354], [87.88171, 48.95853], [87.73822, 48.89582], [88.0788, 48.71436], [87.96361, 48.58478], [88.58939, 48.34531], [88.58316, 48.21893], [88.8011, 48.11302], [88.93186, 48.10263], [89.0711, 47.98528], [89.55453, 48.0423], [89.76624, 47.82745], [90.06512, 47.88177], [90.10871, 47.7375], [90.33598, 47.68303], [90.48854, 47.41826], [90.48542, 47.30438], [90.76108, 46.99399], [90.84035, 46.99525], [91.03649, 46.72916], [91.0147, 46.58171], [91.07696, 46.57315], [90.89639, 46.30711], [90.99672, 46.14207], [91.03026, 46.04194], [90.70907, 45.73437], [90.65114, 45.49314], [90.89169, 45.19667], [91.64048, 45.07408], [93.51161, 44.95964], [94.10003, 44.71016], [94.71959, 44.35284], [95.01191, 44.25274], [95.39772, 44.2805], [95.32891, 44.02407], [95.52594, 43.99353], [95.89543, 43.2528], [96.35658, 42.90363], [96.37926, 42.72055], [97.1777, 42.7964], [99.50671, 42.56535], [100.33297, 42.68231], [100.84979, 42.67087], [101.80515, 42.50074], [102.07645, 42.22519], [102.72403, 42.14675], [103.92804, 41.78246], [104.52258, 41.8706], [104.51667, 41.66113], [105.0123, 41.63188], [106.76517, 42.28741], [107.24774, 42.36107], [107.29755, 42.41395], [107.49681, 42.46221], [107.57258, 42.40898], [108.84489, 42.40246], [109.00679, 42.45302], [109.452, 42.44842], [109.89402, 42.63111], [110.08401, 42.6411], [110.4327, 42.78293], [111.0149, 43.3289], [111.59087, 43.51207], [111.79758, 43.6637], [111.93776, 43.68709], [111.96289, 43.81596], [111.40498, 44.3461], [111.76275, 44.98032], [111.98695, 45.09074], [112.4164, 45.06858], [112.74662, 44.86297], [113.70918, 44.72891], [114.5166, 45.27189], [114.54801, 45.38337], [114.74612, 45.43585], [114.94546, 45.37377], [115.60329, 45.44717], [116.16989, 45.68603], [116.27366, 45.78637], [116.24012, 45.8778], [116.26678, 45.96479], [116.58612, 46.30211], [116.75551, 46.33083], [116.83166, 46.38637], [117.36609, 46.36335], [117.41782, 46.57862], [117.60748, 46.59771], [117.69554, 46.50991], [118.30534, 46.73519], [118.78747, 46.68689], [118.8337, 46.77742], [118.89974, 46.77139], [118.92616, 46.72765], [119.00541, 46.74273], [119.10448, 46.65516], [119.24978, 46.64761], [119.32827, 46.61433], [119.42827, 46.63783], [119.65265, 46.62342], [119.68127, 46.59015], [119.77373, 46.62947], [119.80455, 46.67631], [119.89261, 46.66423], [119.91242, 46.90091], [119.85518, 46.92196], [119.71209, 47.19192], [119.62403, 47.24575], [119.56019, 47.24874], [119.54918, 47.29505], [119.31964, 47.42617], [119.35892, 47.48104], [119.13995, 47.53997], [119.12343, 47.66458], [118.7564, 47.76947], [118.55766, 47.99277], [118.29654, 48.00246], [118.22677, 48.03853], [118.11009, 48.04], [118.03676, 48.00982], [117.80196, 48.01661], [117.50181, 47.77216], [117.37875, 47.63627], [116.9723, 47.87285], [116.67405, 47.89039], [116.4465, 47.83662], [116.21879, 47.88505], [115.94296, 47.67741], [115.57128, 47.91988], [115.52082, 48.15367], [115.811, 48.25699], [115.78876, 48.51781], [116.06565, 48.81716], [116.03781, 48.87014], [116.71193, 49.83813], [116.62502, 49.92919], [116.22402, 50.04477], [115.73602, 49.87688], [115.26068, 49.97367], [114.9703, 50.19254], [114.325, 50.28098], [113.20216, 49.83356], [113.02647, 49.60772], [110.64493, 49.1816], [110.39891, 49.25083], [110.24373, 49.16676], [109.51325, 49.22859], [109.18017, 49.34709], [108.53969, 49.32325], [108.27937, 49.53167], [107.95387, 49.66659], [107.96116, 49.93191], [107.36407, 49.97612], [107.1174, 50.04239], [107.00007, 50.1977], [106.80326, 50.30177], [106.58373, 50.34044], [106.51122, 50.34408], [106.49628, 50.32436], [106.47156, 50.31909], [106.07865, 50.33474], [106.05562, 50.40582], [105.32528, 50.4648], [103.70343, 50.13952], [102.71178, 50.38873], [102.32194, 50.67982], [102.14032, 51.35566]]]]
26168 wikidata: "Q14773",
26170 aliases: ["Macao"],
26172 groups: ["030", "142", "UN"],
26174 callingCodes: ["853"]
26177 type: "MultiPolygon",
26178 coordinates: [[[[113.54942, 22.14519], [113.54839, 22.10909], [113.57191, 22.07696], [113.63011, 22.10782], [113.60504, 22.20464], [113.57123, 22.20416], [113.56865, 22.20973], [113.5508, 22.21672], [113.54333, 22.21688], [113.54093, 22.21314], [113.53593, 22.2137], [113.53301, 22.21235], [113.53552, 22.20607], [113.52659, 22.18271], [113.54093, 22.15497], [113.54942, 22.14519]]]]
26186 wikidata: "Q16644",
26187 nameEn: "Northern Mariana Islands",
26188 aliases: ["US-MP"],
26190 groups: ["Q1352230", "Q153732", "057", "009", "UN"],
26191 roadSpeedUnit: "mph",
26192 callingCodes: ["1 670"]
26195 type: "MultiPolygon",
26196 coordinates: [[[[135.52896, 14.32623], [152.19114, 13.63487], [145.05972, 21.28731], [135.52896, 14.32623]]]]
26204 wikidata: "Q17054",
26205 nameEn: "Martinique",
26207 groups: ["Q3320166", "EU", "029", "003", "419", "019", "UN"],
26208 callingCodes: ["596"]
26211 type: "MultiPolygon",
26212 coordinates: [[[[-59.95997, 14.20285], [-61.07821, 15.25109], [-61.69315, 14.26451], [-59.95997, 14.20285]]]]
26221 nameEn: "Mauritania",
26222 groups: ["011", "202", "002", "UN"],
26223 callingCodes: ["222"]
26226 type: "MultiPolygon",
26227 coordinates: [[[[-5.60725, 16.49919], [-6.57191, 25.0002], [-4.83423, 24.99935], [-8.66674, 27.31569], [-8.66721, 25.99918], [-12.0002, 25.9986], [-12.00251, 23.4538], [-12.14969, 23.41935], [-12.36213, 23.3187], [-12.5741, 23.28975], [-13.00412, 23.02297], [-13.10753, 22.89493], [-13.15313, 22.75649], [-13.08438, 22.53866], [-13.01525, 21.33343], [-16.95474, 21.33997], [-16.99806, 21.12142], [-17.0357, 21.05368], [-17.0396, 20.9961], [-17.06781, 20.92697], [-17.0695, 20.85742], [-17.0471, 20.76408], [-17.15288, 16.07139], [-16.50854, 16.09032], [-16.48967, 16.0496], [-16.44814, 16.09753], [-16.4429, 16.20605], [-16.27016, 16.51565], [-15.6509, 16.50315], [-15.00557, 16.64997], [-14.32144, 16.61495], [-13.80075, 16.13961], [-13.43135, 16.09022], [-13.11029, 15.52116], [-12.23936, 14.76324], [-11.94903, 14.76143], [-11.70705, 15.51558], [-11.43483, 15.62339], [-10.90932, 15.11001], [-10.71721, 15.4223], [-9.40447, 15.4396], [-9.44673, 15.60553], [-9.33314, 15.7044], [-9.31106, 15.69412], [-9.32979, 15.50032], [-5.50165, 15.50061], [-5.33435, 16.33354], [-5.60725, 16.49919]]]]
26235 wikidata: "Q13353",
26236 nameEn: "Montserrat",
26238 groups: ["BOTS", "029", "003", "419", "019", "UN"],
26240 roadSpeedUnit: "mph",
26241 roadHeightUnit: "ft",
26242 callingCodes: ["1 664"]
26245 type: "MultiPolygon",
26246 coordinates: [[[[-61.91508, 16.51165], [-62.1023, 16.97277], [-62.58307, 16.68909], [-61.91508, 16.51165]]]]
26256 groups: ["EU", "039", "150", "UN"],
26258 callingCodes: ["356"]
26261 type: "MultiPolygon",
26262 coordinates: [[[[15.70991, 35.79901], [14.07544, 36.41525], [13.27636, 35.20764], [15.70991, 35.79901]]]]
26271 nameEn: "Mauritius",
26272 groups: ["014", "202", "002", "UN"],
26274 callingCodes: ["230"]
26277 type: "MultiPolygon",
26278 coordinates: [[[[56.09755, -9.55401], [57.50644, -31.92637], [68.4673, -19.15185], [56.09755, -9.55401]]]]
26287 nameEn: "Maldives",
26288 groups: ["034", "142", "UN"],
26290 callingCodes: ["960"]
26293 type: "MultiPolygon",
26294 coordinates: [[[[71.9161, 8.55531], [72.57428, -3.7623], [76.59015, 5.591], [71.9161, 8.55531]]]]
26304 groups: ["014", "202", "002", "UN"],
26306 callingCodes: ["265"]
26309 type: "MultiPolygon",
26310 coordinates: [[[[33.48052, -9.62442], [33.31581, -9.48554], [33.14925, -9.49322], [32.99397, -9.36712], [32.95389, -9.40138], [33.00476, -9.5133], [33.00256, -9.63053], [33.05485, -9.61316], [33.10163, -9.66525], [33.12144, -9.58929], [33.2095, -9.61099], [33.31517, -9.82364], [33.36581, -9.81063], [33.37902, -9.9104], [33.31297, -10.05133], [33.53863, -10.20148], [33.54797, -10.36077], [33.70675, -10.56896], [33.47636, -10.78465], [33.28022, -10.84428], [33.25998, -10.88862], [33.39697, -11.15296], [33.29267, -11.3789], [33.29267, -11.43536], [33.23663, -11.40637], [33.24252, -11.59302], [33.32692, -11.59248], [33.33937, -11.91252], [33.25998, -12.14242], [33.3705, -12.34931], [33.47636, -12.32498], [33.54485, -12.35996], [33.37517, -12.54085], [33.28177, -12.54692], [33.18837, -12.61377], [33.05917, -12.59554], [32.94397, -12.76868], [32.96733, -12.88251], [33.02181, -12.88707], [32.98289, -13.12671], [33.0078, -13.19492], [32.86113, -13.47292], [32.84176, -13.52794], [32.73683, -13.57682], [32.68436, -13.55769], [32.66468, -13.60019], [32.68654, -13.64268], [32.7828, -13.64805], [32.84528, -13.71576], [32.76962, -13.77224], [32.79015, -13.80755], [32.88985, -13.82956], [32.99042, -13.95689], [33.02977, -14.05022], [33.07568, -13.98447], [33.16749, -13.93992], [33.24249, -14.00019], [33.66677, -14.61306], [33.7247, -14.4989], [33.88503, -14.51652], [33.92898, -14.47929], [34.08588, -14.48893], [34.18733, -14.43823], [34.22355, -14.43607], [34.34453, -14.3985], [34.35843, -14.38652], [34.39277, -14.39467], [34.4192, -14.43191], [34.44641, -14.47746], [34.45053, -14.49873], [34.47628, -14.53363], [34.48932, -14.53646], [34.49636, -14.55091], [34.52366, -14.5667], [34.53962, -14.59776], [34.55112, -14.64494], [34.53516, -14.67782], [34.52057, -14.68263], [34.54503, -14.74672], [34.567, -14.77345], [34.61522, -14.99583], [34.57503, -15.30619], [34.43126, -15.44778], [34.44981, -15.60864], [34.25195, -15.90321], [34.43126, -16.04737], [34.40344, -16.20923], [35.04805, -16.83167], [35.13771, -16.81687], [35.17017, -16.93521], [35.04805, -17.00027], [35.0923, -17.13235], [35.3062, -17.1244], [35.27065, -16.93817], [35.30929, -16.82871], [35.27219, -16.69402], [35.14235, -16.56812], [35.25828, -16.4792], [35.30157, -16.2211], [35.43355, -16.11371], [35.52365, -16.15414], [35.70107, -16.10147], [35.80487, -16.03907], [35.85303, -15.41913], [35.78799, -15.17428], [35.91812, -14.89514], [35.87212, -14.89478], [35.86945, -14.67481], [35.5299, -14.27714], [35.47989, -14.15594], [34.86229, -13.48958], [34.60253, -13.48487], [34.37831, -12.17408], [34.46088, -12.0174], [34.70739, -12.15652], [34.82903, -12.04837], [34.57917, -11.87849], [34.64241, -11.57499], [34.96296, -11.57354], [34.91153, -11.39799], [34.79375, -11.32245], [34.63305, -11.11731], [34.61161, -11.01611], [34.67047, -10.93796], [34.65946, -10.6828], [34.57581, -10.56271], [34.51911, -10.12279], [34.54499, -10.0678], [34.03865, -9.49398], [33.95829, -9.54066], [33.9638, -9.62206], [33.93298, -9.71647], [33.76677, -9.58516], [33.48052, -9.62442]]]]
26320 groups: ["013", "003", "419", "019", "UN"],
26321 callingCodes: ["52"]
26324 type: "MultiPolygon",
26325 coordinates: [[[[-117.1243, 32.53427], [-118.48109, 32.5991], [-120.12904, 18.41089], [-92.37213, 14.39277], [-92.2261, 14.53423], [-92.1454, 14.6804], [-92.18161, 14.84147], [-92.1423, 14.88647], [-92.1454, 14.98143], [-92.0621, 15.07406], [-92.20983, 15.26077], [-91.73182, 16.07371], [-90.44567, 16.07573], [-90.40499, 16.40524], [-90.61212, 16.49832], [-90.69064, 16.70697], [-91.04436, 16.92175], [-91.43809, 17.25373], [-90.99199, 17.25192], [-90.98678, 17.81655], [-89.14985, 17.81563], [-89.15105, 17.95104], [-89.03839, 18.0067], [-88.8716, 17.89535], [-88.71505, 18.0707], [-88.48242, 18.49164], [-88.3268, 18.49048], [-88.29909, 18.47591], [-88.26593, 18.47617], [-88.03238, 18.41778], [-88.03165, 18.16657], [-87.90671, 18.15213], [-87.87604, 18.18313], [-87.86657, 18.19971], [-87.85693, 18.18266], [-87.84815, 18.18511], [-86.92368, 17.61462], [-85.9092, 21.8218], [-96.92418, 25.97377], [-97.13927, 25.96583], [-97.35946, 25.92189], [-97.37332, 25.83854], [-97.42511, 25.83969], [-97.45669, 25.86874], [-97.49828, 25.89877], [-97.52025, 25.88518], [-97.66511, 26.01708], [-97.95155, 26.0625], [-97.97017, 26.05232], [-98.24603, 26.07191], [-98.27075, 26.09457], [-98.30491, 26.10475], [-98.35126, 26.15129], [-99.00546, 26.3925], [-99.03053, 26.41249], [-99.08477, 26.39849], [-99.53573, 27.30926], [-99.49744, 27.43746], [-99.482, 27.47128], [-99.48045, 27.49016], [-99.50208, 27.50021], [-99.52955, 27.49747], [-99.51478, 27.55836], [-99.55409, 27.61314], [-100.50029, 28.66117], [-100.51222, 28.70679], [-100.5075, 28.74066], [-100.52313, 28.75598], [-100.59809, 28.88197], [-100.63689, 28.90812], [-100.67294, 29.09744], [-100.79696, 29.24688], [-100.87982, 29.296], [-100.94056, 29.33371], [-100.94579, 29.34523], [-100.96725, 29.3477], [-101.01128, 29.36947], [-101.05686, 29.44738], [-101.47277, 29.7744], [-102.60596, 29.8192], [-103.15787, 28.93865], [-104.37752, 29.54255], [-104.39363, 29.55396], [-104.3969, 29.57105], [-104.5171, 29.64671], [-104.77674, 30.4236], [-106.00363, 31.39181], [-106.09025, 31.40569], [-106.20346, 31.46305], [-106.23711, 31.51262], [-106.24612, 31.54193], [-106.28084, 31.56173], [-106.30305, 31.62154], [-106.33419, 31.66303], [-106.34864, 31.69663], [-106.3718, 31.71165], [-106.38003, 31.73151], [-106.41773, 31.75196], [-106.43419, 31.75478], [-106.45244, 31.76523], [-106.46726, 31.75998], [-106.47298, 31.75054], [-106.48815, 31.74769], [-106.50111, 31.75714], [-106.50962, 31.76155], [-106.51251, 31.76922], [-106.52266, 31.77509], [-106.529, 31.784], [-108.20899, 31.78534], [-108.20979, 31.33316], [-111.07523, 31.33232], [-114.82011, 32.49609], [-114.79524, 32.55731], [-114.81141, 32.55543], [-114.80584, 32.62028], [-114.76736, 32.64094], [-114.71871, 32.71894], [-115.88053, 32.63624], [-117.1243, 32.53427]]]]
26344 nameEn: "Mozambique",
26345 groups: ["014", "202", "002", "UN"],
26347 callingCodes: ["258"]
26350 type: "MultiPolygon",
26351 coordinates: [[[[40.74206, -10.25691], [40.44265, -10.4618], [40.00295, -10.80255], [39.58249, -10.96043], [39.24395, -11.17433], [38.88996, -11.16978], [38.47258, -11.4199], [38.21598, -11.27289], [37.93618, -11.26228], [37.8388, -11.3123], [37.76614, -11.53352], [37.3936, -11.68949], [36.80309, -11.56836], [36.62068, -11.72884], [36.19094, -11.70008], [36.19094, -11.57593], [35.82767, -11.41081], [35.63599, -11.55927], [34.96296, -11.57354], [34.64241, -11.57499], [34.57917, -11.87849], [34.82903, -12.04837], [34.70739, -12.15652], [34.46088, -12.0174], [34.37831, -12.17408], [34.60253, -13.48487], [34.86229, -13.48958], [35.47989, -14.15594], [35.5299, -14.27714], [35.86945, -14.67481], [35.87212, -14.89478], [35.91812, -14.89514], [35.78799, -15.17428], [35.85303, -15.41913], [35.80487, -16.03907], [35.70107, -16.10147], [35.52365, -16.15414], [35.43355, -16.11371], [35.30157, -16.2211], [35.25828, -16.4792], [35.14235, -16.56812], [35.27219, -16.69402], [35.30929, -16.82871], [35.27065, -16.93817], [35.3062, -17.1244], [35.0923, -17.13235], [35.04805, -17.00027], [35.17017, -16.93521], [35.13771, -16.81687], [35.04805, -16.83167], [34.40344, -16.20923], [34.43126, -16.04737], [34.25195, -15.90321], [34.44981, -15.60864], [34.43126, -15.44778], [34.57503, -15.30619], [34.61522, -14.99583], [34.567, -14.77345], [34.54503, -14.74672], [34.52057, -14.68263], [34.53516, -14.67782], [34.55112, -14.64494], [34.53962, -14.59776], [34.52366, -14.5667], [34.49636, -14.55091], [34.48932, -14.53646], [34.47628, -14.53363], [34.45053, -14.49873], [34.44641, -14.47746], [34.4192, -14.43191], [34.39277, -14.39467], [34.35843, -14.38652], [34.34453, -14.3985], [34.22355, -14.43607], [34.18733, -14.43823], [34.08588, -14.48893], [33.92898, -14.47929], [33.88503, -14.51652], [33.7247, -14.4989], [33.66677, -14.61306], [33.24249, -14.00019], [30.22098, -14.99447], [30.41902, -15.62269], [30.42568, -15.9962], [30.91597, -15.99924], [30.97761, -16.05848], [31.13171, -15.98019], [31.30563, -16.01193], [31.42451, -16.15154], [31.67988, -16.19595], [31.90223, -16.34388], [31.91324, -16.41569], [32.02772, -16.43892], [32.28529, -16.43892], [32.42838, -16.4727], [32.71017, -16.59932], [32.69917, -16.66893], [32.78943, -16.70267], [32.97655, -16.70689], [32.91051, -16.89446], [32.84113, -16.92259], [32.96554, -17.11971], [33.00517, -17.30477], [33.0426, -17.3468], [32.96554, -17.48964], [32.98536, -17.55891], [33.0492, -17.60298], [32.94133, -17.99705], [33.03159, -18.35054], [33.02278, -18.4696], [32.88629, -18.51344], [32.88629, -18.58023], [32.95013, -18.69079], [32.9017, -18.7992], [32.82465, -18.77419], [32.70137, -18.84712], [32.73439, -18.92628], [32.69917, -18.94293], [32.72118, -19.02204], [32.84006, -19.0262], [32.87088, -19.09279], [32.85107, -19.29238], [32.77966, -19.36098], [32.78282, -19.47513], [32.84446, -19.48343], [32.84666, -19.68462], [32.95013, -19.67219], [33.06461, -19.77787], [33.01178, -20.02007], [32.93032, -20.03868], [32.85987, -20.16686], [32.85987, -20.27841], [32.66174, -20.56106], [32.55167, -20.56312], [32.48122, -20.63319], [32.51644, -20.91929], [32.37115, -21.133], [32.48236, -21.32873], [32.41234, -21.31246], [31.38336, -22.36919], [31.30611, -22.422], [31.55779, -23.176], [31.56539, -23.47268], [31.67942, -23.60858], [31.70223, -23.72695], [31.77445, -23.90082], [31.87707, -23.95293], [31.90368, -24.18892], [31.9835, -24.29983], [32.03196, -25.10785], [32.01676, -25.38117], [31.97875, -25.46356], [32.00631, -25.65044], [31.92649, -25.84216], [31.974, -25.95387], [32.00916, -25.999], [32.08599, -26.00978], [32.10435, -26.15656], [32.07352, -26.40185], [32.13409, -26.5317], [32.13315, -26.84345], [32.19409, -26.84032], [32.22302, -26.84136], [32.29584, -26.852], [32.35222, -26.86027], [34.51034, -26.91792], [42.99868, -12.65261], [40.74206, -10.25691]]]]
26361 groups: ["018", "202", "002", "UN"],
26363 callingCodes: ["264"]
26366 type: "MultiPolygon",
26367 coordinates: [[[[14.28743, -17.38814], [13.95896, -17.43141], [13.36212, -16.98048], [12.97145, -16.98567], [12.52111, -17.24495], [12.07076, -17.15165], [11.75063, -17.25013], [10.5065, -17.25284], [12.51595, -32.27486], [16.45332, -28.63117], [16.46592, -28.57126], [16.59922, -28.53246], [16.90446, -28.057], [17.15405, -28.08573], [17.4579, -28.68718], [18.99885, -28.89165], [19.99882, -28.42622], [19.99817, -24.76768], [19.99912, -21.99991], [20.99751, -22.00026], [20.99904, -18.31743], [21.45556, -18.31795], [23.0996, -18.00075], [23.29618, -17.99855], [23.61088, -18.4881], [24.19416, -18.01919], [24.40577, -17.95726], [24.57485, -18.07151], [24.6303, -17.9863], [24.71887, -17.9218], [24.73364, -17.89338], [24.95586, -17.79674], [25.05895, -17.84452], [25.16882, -17.78253], [25.26433, -17.79571], [25.00198, -17.58221], [24.70864, -17.49501], [24.5621, -17.52963], [24.38712, -17.46818], [24.32811, -17.49082], [24.23619, -17.47489], [23.47474, -17.62877], [21.42741, -18.02787], [21.14283, -17.94318], [18.84226, -17.80375], [18.39229, -17.38927], [14.28743, -17.38814]]]]
26375 wikidata: "Q33788",
26376 nameEn: "New Caledonia",
26378 groups: ["Q1451600", "054", "009", "UN"],
26379 callingCodes: ["687"]
26382 type: "MultiPolygon",
26383 coordinates: [[[[159.77159, -28.41151], [174.245, -23.1974], [156.73836, -14.50464], [159.77159, -28.41151]]]]
26394 groups: ["011", "202", "002", "UN"],
26395 callingCodes: ["227"]
26398 type: "MultiPolygon",
26399 coordinates: [[[[14.22918, 22.61719], [13.5631, 23.16574], [11.96886, 23.51735], [7.48273, 20.87258], [7.38361, 20.79165], [5.8153, 19.45101], [4.26651, 19.14224], [4.26762, 17.00432], [4.21787, 17.00118], [4.19893, 16.39923], [3.50368, 15.35934], [3.03134, 15.42221], [3.01806, 15.34571], [1.31275, 15.27978], [0.96711, 14.98275], [0.72632, 14.95898], [0.23859, 15.00135], [0.16936, 14.51654], [0.38051, 14.05575], [0.61924, 13.68491], [0.77377, 13.6866], [0.77637, 13.64442], [0.99514, 13.5668], [1.02813, 13.46635], [1.20088, 13.38951], [1.24429, 13.39373], [1.28509, 13.35488], [1.24516, 13.33968], [1.21217, 13.37853], [1.18873, 13.31771], [0.99253, 13.37515], [0.99167, 13.10727], [2.26349, 12.41915], [2.05785, 12.35539], [2.39723, 11.89473], [2.45824, 11.98672], [2.39657, 12.10952], [2.37783, 12.24804], [2.6593, 12.30631], [2.83978, 12.40585], [3.25352, 12.01467], [3.31613, 11.88495], [3.48187, 11.86092], [3.59375, 11.70269], [3.61075, 11.69181], [3.67988, 11.75429], [3.67122, 11.80865], [3.63063, 11.83042], [3.61955, 11.91847], [3.67775, 11.97599], [3.63136, 12.11826], [3.66364, 12.25884], [3.65111, 12.52223], [3.94339, 12.74979], [4.10006, 12.98862], [4.14367, 13.17189], [4.14186, 13.47586], [4.23456, 13.47725], [4.4668, 13.68286], [4.87425, 13.78], [4.9368, 13.7345], [5.07396, 13.75052], [5.21026, 13.73627], [5.27797, 13.75474], [5.35437, 13.83567], [5.52957, 13.8845], [6.15771, 13.64564], [6.27411, 13.67835], [6.43053, 13.6006], [6.69617, 13.34057], [6.94445, 12.99825], [7.0521, 13.00076], [7.12676, 13.02445], [7.22399, 13.1293], [7.39241, 13.09717], [7.81085, 13.34902], [8.07997, 13.30847], [8.25185, 13.20369], [8.41853, 13.06166], [8.49493, 13.07519], [8.60431, 13.01768], [8.64251, 12.93985], [8.97413, 12.83661], [9.65995, 12.80614], [10.00373, 13.18171], [10.19993, 13.27129], [10.46731, 13.28819], [10.66004, 13.36422], [11.4535, 13.37773], [11.88236, 13.2527], [12.04209, 13.14452], [12.16189, 13.10056], [12.19315, 13.12423], [12.47095, 13.06673], [12.58033, 13.27805], [12.6793, 13.29157], [12.87376, 13.48919], [13.05085, 13.53984], [13.19844, 13.52802], [13.33213, 13.71195], [13.6302, 13.71094], [13.47559, 14.40881], [13.48259, 14.46704], [13.68573, 14.55276], [13.67878, 14.64013], [13.809, 14.72915], [13.78991, 14.87519], [13.86301, 15.04043], [14.37425, 15.72591], [15.50373, 16.89649], [15.6032, 18.77402], [15.75098, 19.93002], [15.99632, 20.35364], [15.6721, 20.70069], [15.59841, 20.74039], [15.56004, 20.79488], [15.55382, 20.86507], [15.57248, 20.92138], [15.62515, 20.95395], [15.28332, 21.44557], [15.20213, 21.49365], [15.19692, 21.99339], [14.99751, 23.00539], [14.22918, 22.61719]]]]
26407 wikidata: "Q31057",
26408 nameEn: "Norfolk Island",
26410 groups: ["053", "009", "UN"],
26412 callingCodes: ["672 3"]
26415 type: "MultiPolygon",
26416 coordinates: [[[[169.82316, -28.16667], [166.29505, -28.29175], [167.94076, -30.60745], [169.82316, -28.16667]]]]
26426 groups: ["011", "202", "002", "UN"],
26427 callingCodes: ["234"]
26430 type: "MultiPolygon",
26431 coordinates: [[[[6.15771, 13.64564], [5.52957, 13.8845], [5.35437, 13.83567], [5.27797, 13.75474], [5.21026, 13.73627], [5.07396, 13.75052], [4.9368, 13.7345], [4.87425, 13.78], [4.4668, 13.68286], [4.23456, 13.47725], [4.14186, 13.47586], [4.14367, 13.17189], [4.10006, 12.98862], [3.94339, 12.74979], [3.65111, 12.52223], [3.66364, 12.25884], [3.63136, 12.11826], [3.67775, 11.97599], [3.61955, 11.91847], [3.63063, 11.83042], [3.67122, 11.80865], [3.67988, 11.75429], [3.61075, 11.69181], [3.59375, 11.70269], [3.49175, 11.29765], [3.71505, 11.13015], [3.84243, 10.59316], [3.78292, 10.40538], [3.6844, 10.46351], [3.57275, 10.27185], [3.66908, 10.18136], [3.54429, 9.87739], [3.35383, 9.83641], [3.32099, 9.78032], [3.34726, 9.70696], [3.25093, 9.61632], [3.13928, 9.47167], [3.14147, 9.28375], [3.08017, 9.10006], [2.77907, 9.06924], [2.67523, 7.87825], [2.73095, 7.7755], [2.73405, 7.5423], [2.78668, 7.5116], [2.79442, 7.43486], [2.74489, 7.42565], [2.76965, 7.13543], [2.71702, 6.95722], [2.74024, 6.92802], [2.73405, 6.78508], [2.78823, 6.76356], [2.78204, 6.70514], [2.7325, 6.64057], [2.74334, 6.57291], [2.70464, 6.50831], [2.70566, 6.38038], [2.74181, 6.13349], [5.87055, 3.78489], [8.34397, 4.30689], [8.60302, 4.87353], [8.78027, 5.1243], [8.92029, 5.58403], [8.83687, 5.68483], [8.88156, 5.78857], [8.84209, 5.82562], [9.51757, 6.43874], [9.70674, 6.51717], [9.77824, 6.79088], [9.86314, 6.77756], [10.15135, 7.03781], [10.21466, 6.88996], [10.53639, 6.93432], [10.57214, 7.16345], [10.59746, 7.14719], [10.60789, 7.06885], [10.83727, 6.9358], [10.8179, 6.83377], [10.94302, 6.69325], [11.09644, 6.68437], [11.09495, 6.51717], [11.42041, 6.53789], [11.42264, 6.5882], [11.51499, 6.60892], [11.57755, 6.74059], [11.55818, 6.86186], [11.63117, 6.9905], [11.87396, 7.09398], [11.84864, 7.26098], [11.93205, 7.47812], [12.01844, 7.52981], [11.99908, 7.67302], [12.20909, 7.97553], [12.19271, 8.10826], [12.24782, 8.17904], [12.26123, 8.43696], [12.4489, 8.52536], [12.44146, 8.6152], [12.68722, 8.65938], [12.71701, 8.7595], [12.79, 8.75361], [12.81085, 8.91992], [12.90022, 9.11411], [12.91958, 9.33905], [12.85628, 9.36698], [13.02385, 9.49334], [13.22642, 9.57266], [13.25472, 9.76795], [13.29941, 9.8296], [13.25025, 9.86042], [13.24132, 9.91031], [13.27409, 9.93232], [13.286, 9.9822], [13.25323, 10.00127], [13.25025, 10.03647], [13.34111, 10.12299], [13.43644, 10.13326], [13.5705, 10.53183], [13.54964, 10.61236], [13.73434, 10.9255], [13.70753, 10.94451], [13.7403, 11.00593], [13.78945, 11.00154], [13.97489, 11.30258], [14.17821, 11.23831], [14.6124, 11.51283], [14.64591, 11.66166], [14.55207, 11.72001], [14.61612, 11.7798], [14.6474, 12.17466], [14.4843, 12.35223], [14.22215, 12.36533], [14.17523, 12.41916], [14.20204, 12.53405], [14.08251, 13.0797], [13.6302, 13.71094], [13.33213, 13.71195], [13.19844, 13.52802], [13.05085, 13.53984], [12.87376, 13.48919], [12.6793, 13.29157], [12.58033, 13.27805], [12.47095, 13.06673], [12.19315, 13.12423], [12.16189, 13.10056], [12.04209, 13.14452], [11.88236, 13.2527], [11.4535, 13.37773], [10.66004, 13.36422], [10.46731, 13.28819], [10.19993, 13.27129], [10.00373, 13.18171], [9.65995, 12.80614], [8.97413, 12.83661], [8.64251, 12.93985], [8.60431, 13.01768], [8.49493, 13.07519], [8.41853, 13.06166], [8.25185, 13.20369], [8.07997, 13.30847], [7.81085, 13.34902], [7.39241, 13.09717], [7.22399, 13.1293], [7.12676, 13.02445], [7.0521, 13.00076], [6.94445, 12.99825], [6.69617, 13.34057], [6.43053, 13.6006], [6.27411, 13.67835], [6.15771, 13.64564]]]]
26440 nameEn: "Nicaragua",
26441 groups: ["013", "003", "419", "019", "UN"],
26442 callingCodes: ["505"]
26445 type: "MultiPolygon",
26446 coordinates: [[[[-83.13724, 15.00002], [-83.49268, 15.01158], [-83.62101, 14.89448], [-83.89551, 14.76697], [-84.10584, 14.76353], [-84.48373, 14.63249], [-84.70119, 14.68078], [-84.82596, 14.82212], [-84.90082, 14.80489], [-85.1575, 14.53934], [-85.18602, 14.24929], [-85.32149, 14.2562], [-85.45762, 14.11304], [-85.73964, 13.9698], [-85.75477, 13.8499], [-86.03458, 13.99181], [-86.00685, 14.08474], [-86.14801, 14.04317], [-86.35219, 13.77157], [-86.76812, 13.79605], [-86.71267, 13.30348], [-86.87066, 13.30641], [-86.93383, 13.18677], [-86.93197, 13.05313], [-87.03785, 12.98682], [-87.06306, 13.00892], [-87.37107, 12.98646], [-87.55124, 13.12523], [-87.7346, 13.13228], [-88.11443, 12.63306], [-86.14524, 11.09059], [-85.71223, 11.06868], [-85.60529, 11.22607], [-84.92439, 10.9497], [-84.68197, 11.07568], [-83.90838, 10.71161], [-83.66597, 10.79916], [-83.68276, 11.01562], [-82.56142, 11.91792], [-82.06974, 14.49418], [-83.04763, 15.03256], [-83.13724, 15.00002]]]]
26454 wikidata: "Q29999",
26455 nameEn: "Kingdom of the Netherlands"
26476 groups: ["034", "142", "UN"],
26478 callingCodes: ["977"]
26481 type: "MultiPolygon",
26482 coordinates: [[[[88.13378, 27.88015], [87.82681, 27.95248], [87.72718, 27.80938], [87.56996, 27.84517], [87.11696, 27.84104], [87.03757, 27.94835], [86.75582, 28.04182], [86.74181, 28.10638], [86.56265, 28.09569], [86.51609, 27.96623], [86.42736, 27.91122], [86.22966, 27.9786], [86.18607, 28.17364], [86.088, 28.09264], [86.08333, 28.02121], [86.12069, 27.93047], [86.06309, 27.90021], [85.94946, 27.9401], [85.97813, 27.99023], [85.90743, 28.05144], [85.84672, 28.18187], [85.74864, 28.23126], [85.71907, 28.38064], [85.69105, 28.38475], [85.60854, 28.25045], [85.59765, 28.30529], [85.4233, 28.32996], [85.38127, 28.28336], [85.10729, 28.34092], [85.18668, 28.54076], [85.19135, 28.62825], [85.06059, 28.68562], [84.85511, 28.58041], [84.62317, 28.73887], [84.47528, 28.74023], [84.2231, 28.89571], [84.24801, 29.02783], [84.18107, 29.23451], [83.97559, 29.33091], [83.82303, 29.30513], [83.63156, 29.16249], [83.44787, 29.30513], [83.28131, 29.56813], [83.07116, 29.61957], [82.73024, 29.81695], [82.5341, 29.9735], [82.38622, 30.02608], [82.16984, 30.0692], [82.19475, 30.16884], [82.10757, 30.23745], [82.10135, 30.35439], [81.99082, 30.33423], [81.62033, 30.44703], [81.5459, 30.37688], [81.41018, 30.42153], [81.39928, 30.21862], [81.33355, 30.15303], [81.2623, 30.14596], [81.29032, 30.08806], [81.24362, 30.0126], [81.12842, 30.01395], [81.03953, 30.20059], [80.92547, 30.17193], [80.91143, 30.22173], [80.86673, 30.17321], [80.8778, 30.13384], [80.67076, 29.95732], [80.60226, 29.95732], [80.57179, 29.91422], [80.56247, 29.86661], [80.48997, 29.79566], [80.43458, 29.80466], [80.41554, 29.79451], [80.36803, 29.73865], [80.38428, 29.68513], [80.41858, 29.63581], [80.37939, 29.57098], [80.24322, 29.44299], [80.31428, 29.30784], [80.28626, 29.20327], [80.24112, 29.21414], [80.26602, 29.13938], [80.23178, 29.11626], [80.18085, 29.13649], [80.05743, 28.91479], [80.06957, 28.82763], [80.12125, 28.82346], [80.37188, 28.63371], [80.44504, 28.63098], [80.52443, 28.54897], [80.50575, 28.6706], [80.55142, 28.69182], [81.03471, 28.40054], [81.19847, 28.36284], [81.32923, 28.13521], [81.38683, 28.17638], [81.48179, 28.12148], [81.47867, 28.08303], [81.91223, 27.84995], [81.97214, 27.93322], [82.06554, 27.92222], [82.46405, 27.6716], [82.70378, 27.72122], [82.74119, 27.49838], [82.93261, 27.50328], [82.94938, 27.46036], [83.19413, 27.45632], [83.27197, 27.38309], [83.2673, 27.36235], [83.29999, 27.32778], [83.35136, 27.33885], [83.38872, 27.39276], [83.39495, 27.4798], [83.61288, 27.47013], [83.85595, 27.35797], [83.86182, 27.4241], [83.93306, 27.44939], [84.02229, 27.43836], [84.10791, 27.52399], [84.21376, 27.45218], [84.25735, 27.44941], [84.29315, 27.39], [84.62161, 27.33885], [84.69166, 27.21294], [84.64496, 27.04669], [84.793, 26.9968], [84.82913, 27.01989], [84.85754, 26.98984], [84.96687, 26.95599], [84.97186, 26.9149], [85.00536, 26.89523], [85.05592, 26.88991], [85.02635, 26.85381], [85.15883, 26.86966], [85.19291, 26.86909], [85.18046, 26.80519], [85.21159, 26.75933], [85.34302, 26.74954], [85.47752, 26.79292], [85.56471, 26.84133], [85.5757, 26.85955], [85.59461, 26.85161], [85.61621, 26.86721], [85.66239, 26.84822], [85.73483, 26.79613], [85.72315, 26.67471], [85.76907, 26.63076], [85.83126, 26.61134], [85.85126, 26.60866], [85.8492, 26.56667], [86.02729, 26.66756], [86.13596, 26.60651], [86.22513, 26.58863], [86.26235, 26.61886], [86.31564, 26.61925], [86.49726, 26.54218], [86.54258, 26.53819], [86.57073, 26.49825], [86.61313, 26.48658], [86.62686, 26.46891], [86.69124, 26.45169], [86.74025, 26.42386], [86.76797, 26.45892], [86.82898, 26.43919], [86.94543, 26.52076], [86.95912, 26.52076], [87.01559, 26.53228], [87.04691, 26.58685], [87.0707, 26.58571], [87.09147, 26.45039], [87.14751, 26.40542], [87.18863, 26.40558], [87.24682, 26.4143], [87.26587, 26.40592], [87.26568, 26.37294], [87.34568, 26.34787], [87.37314, 26.40815], [87.46566, 26.44058], [87.51571, 26.43106], [87.55274, 26.40596], [87.59175, 26.38342], [87.66803, 26.40294], [87.67893, 26.43501], [87.76004, 26.40711], [87.7918, 26.46737], [87.84193, 26.43663], [87.89085, 26.48565], [87.90115, 26.44923], [88.00895, 26.36029], [88.09414, 26.43732], [88.09963, 26.54195], [88.16452, 26.64111], [88.1659, 26.68177], [88.19107, 26.75516], [88.12302, 26.95324], [88.13422, 26.98705], [88.11719, 26.98758], [87.9887, 27.11045], [88.01587, 27.21388], [88.01646, 27.21612], [88.07277, 27.43007], [88.04008, 27.49223], [88.19107, 27.79285], [88.1973, 27.85067], [88.13378, 27.88015]]]]
26492 groups: ["057", "009", "UN"],
26494 callingCodes: ["674"]
26497 type: "MultiPolygon",
26498 coordinates: [[[[166.95155, 0.14829], [166.21778, -0.7977], [167.60042, -0.88259], [166.95155, 0.14829]]]]
26506 wikidata: "Q34020",
26509 groups: ["061", "009", "UN"],
26511 callingCodes: ["683"]
26514 type: "MultiPolygon",
26515 coordinates: [[[[-170.83899, -18.53439], [-170.82274, -20.44429], [-168.63096, -18.60489], [-170.83899, -18.53439]]]]
26524 nameEn: "New Zealand"
26535 groups: ["145", "142", "UN"],
26536 callingCodes: ["968"]
26539 type: "MultiPolygon",
26540 coordinates: [[[[56.82555, 25.7713], [56.79239, 26.41236], [56.68954, 26.76645], [56.2644, 26.58649], [55.81777, 26.18798], [56.08666, 26.05038], [56.15498, 26.06828], [56.19334, 25.9795], [56.13963, 25.82765], [56.17416, 25.77239], [56.13579, 25.73524], [56.14826, 25.66351], [56.18363, 25.65508], [56.20473, 25.61119], [56.25365, 25.60211], [56.26636, 25.60643], [56.25341, 25.61443], [56.26534, 25.62825], [56.82555, 25.7713]]], [[[56.26062, 25.33108], [56.23362, 25.31253], [56.25008, 25.28843], [56.24465, 25.27505], [56.20838, 25.25668], [56.20872, 25.24104], [56.24341, 25.22867], [56.27628, 25.23404], [56.34438, 25.26653], [56.35172, 25.30681], [56.3111, 25.30107], [56.3005, 25.31815], [56.26062, 25.33108]], [[56.28423, 25.26344], [56.27086, 25.26128], [56.2716, 25.27916], [56.28102, 25.28486], [56.29379, 25.2754], [56.28423, 25.26344]]], [[[61.45114, 22.55394], [56.86325, 25.03856], [56.3227, 24.97284], [56.34873, 24.93205], [56.30269, 24.88334], [56.20568, 24.85063], [56.20062, 24.78565], [56.13684, 24.73699], [56.06128, 24.74457], [56.03535, 24.81161], [55.97836, 24.87673], [55.97467, 24.89639], [56.05106, 24.87461], [56.05715, 24.95727], [55.96316, 25.00857], [55.90849, 24.96771], [55.85094, 24.96858], [55.81116, 24.9116], [55.81348, 24.80102], [55.83408, 24.77858], [55.83271, 24.68567], [55.76461, 24.5287], [55.83271, 24.41521], [55.83395, 24.32776], [55.80747, 24.31069], [55.79145, 24.27914], [55.76781, 24.26209], [55.75939, 24.26114], [55.75382, 24.2466], [55.75257, 24.23466], [55.76558, 24.23227], [55.77658, 24.23476], [55.83367, 24.20193], [55.95472, 24.2172], [56.01799, 24.07426], [55.8308, 24.01633], [55.73301, 24.05994], [55.48677, 23.94946], [55.57358, 23.669], [55.22634, 23.10378], [55.2137, 22.71065], [55.66469, 21.99658], [54.99756, 20.00083], [52.00311, 19.00083], [52.78009, 17.35124], [52.74267, 17.29519], [52.81185, 17.28568], [57.49095, 8.14549], [61.45114, 22.55394]]]]
26550 groups: ["013", "003", "419", "019", "UN"],
26551 callingCodes: ["507"]
26554 type: "MultiPolygon",
26555 coordinates: [[[[-77.32389, 8.81247], [-77.58292, 9.22278], [-78.79327, 9.93766], [-82.51044, 9.65379], [-82.56507, 9.57279], [-82.61345, 9.49881], [-82.66667, 9.49746], [-82.77206, 9.59573], [-82.87919, 9.62645], [-82.84871, 9.4973], [-82.93516, 9.46741], [-82.93516, 9.07687], [-82.72126, 8.97125], [-82.88253, 8.83331], [-82.91377, 8.774], [-82.92068, 8.74832], [-82.8794, 8.6981], [-82.82739, 8.60153], [-82.83975, 8.54755], [-82.83322, 8.52464], [-82.8382, 8.48117], [-82.8679, 8.44042], [-82.93056, 8.43465], [-83.05209, 8.33394], [-82.9388, 8.26634], [-82.88641, 8.10219], [-82.89137, 8.05755], [-82.89978, 8.04083], [-82.94503, 7.93865], [-82.13751, 6.97312], [-78.06168, 7.07793], [-77.89178, 7.22681], [-77.81426, 7.48319], [-77.72157, 7.47612], [-77.72514, 7.72348], [-77.57185, 7.51147], [-77.17257, 7.97422], [-77.45064, 8.49991], [-77.32389, 8.81247]]]]
26565 groups: ["005", "419", "019", "UN"],
26566 callingCodes: ["51"]
26569 type: "MultiPolygon",
26570 coordinates: [[[[-74.26675, -0.97229], [-74.42701, -0.50218], [-75.18513, -0.0308], [-75.25764, -0.11943], [-75.40192, -0.17196], [-75.61997, -0.10012], [-75.60169, -0.18708], [-75.53615, -0.19213], [-75.22862, -0.60048], [-75.22862, -0.95588], [-75.3872, -0.9374], [-75.57429, -1.55961], [-76.05203, -2.12179], [-76.6324, -2.58397], [-77.94147, -3.05454], [-78.19369, -3.36431], [-78.14324, -3.47653], [-78.22642, -3.51113], [-78.24589, -3.39907], [-78.34362, -3.38633], [-78.68394, -4.60754], [-78.85149, -4.66795], [-79.01659, -5.01481], [-79.1162, -4.97774], [-79.26248, -4.95167], [-79.59402, -4.46848], [-79.79722, -4.47558], [-80.13945, -4.29786], [-80.39256, -4.48269], [-80.46386, -4.41516], [-80.32114, -4.21323], [-80.45023, -4.20938], [-80.4822, -4.05477], [-80.46386, -4.01342], [-80.13232, -3.90317], [-80.19926, -3.68894], [-80.18741, -3.63994], [-80.19848, -3.59249], [-80.21642, -3.5888], [-80.20535, -3.51667], [-80.22629, -3.501], [-80.23651, -3.48652], [-80.24586, -3.48677], [-80.24123, -3.46124], [-80.20647, -3.431], [-80.30602, -3.39149], [-84.52388, -3.36941], [-85.71054, -21.15413], [-70.59118, -18.35072], [-70.378, -18.3495], [-70.31267, -18.31258], [-70.16394, -18.31737], [-69.96732, -18.25992], [-69.81607, -18.12582], [-69.75305, -17.94605], [-69.82868, -17.72048], [-69.79087, -17.65563], [-69.66483, -17.65083], [-69.46897, -17.4988], [-69.46863, -17.37466], [-69.62883, -17.28142], [-69.16896, -16.72233], [-69.00853, -16.66769], [-69.04027, -16.57214], [-68.98358, -16.42165], [-68.79464, -16.33272], [-68.96238, -16.194], [-69.09986, -16.22693], [-69.20291, -16.16668], [-69.40336, -15.61358], [-69.14856, -15.23478], [-69.36254, -14.94634], [-68.88135, -14.18639], [-69.05265, -13.68546], [-68.8864, -13.40792], [-68.85615, -12.87769], [-68.65044, -12.50689], [-68.98115, -11.8979], [-69.57156, -10.94555], [-69.57835, -10.94051], [-69.90896, -10.92744], [-70.38791, -11.07096], [-70.51395, -10.92249], [-70.64134, -11.0108], [-70.62487, -9.80666], [-70.55429, -9.76692], [-70.58453, -9.58303], [-70.53373, -9.42628], [-71.23394, -9.9668], [-72.14742, -9.98049], [-72.31883, -9.5184], [-72.72216, -9.41397], [-73.21498, -9.40904], [-72.92886, -9.04074], [-73.76576, -7.89884], [-73.65485, -7.77897], [-73.96938, -7.58465], [-73.77011, -7.28944], [-73.73986, -6.87919], [-73.12983, -6.43852], [-73.24579, -6.05764], [-72.83973, -5.14765], [-72.64391, -5.0391], [-71.87003, -4.51661], [-70.96814, -4.36915], [-70.77601, -4.15717], [-70.33236, -4.15214], [-70.19582, -4.3607], [-70.11305, -4.27281], [-70.00888, -4.37833], [-69.94708, -4.2431], [-70.3374, -3.79505], [-70.52393, -3.87553], [-70.71396, -3.7921], [-70.04609, -2.73906], [-70.94377, -2.23142], [-71.75223, -2.15058], [-72.92587, -2.44514], [-73.65312, -1.26222], [-74.26675, -0.97229]]]]
26578 wikidata: "Q30971",
26579 nameEn: "French Polynesia",
26581 groups: ["Q1451600", "061", "009", "UN"],
26582 callingCodes: ["689"]
26585 type: "MultiPolygon",
26586 coordinates: [[[[-135.59706, -4.70473], [-156.48634, -15.52824], [-156.45576, -31.75456], [-133.59543, -28.4709], [-135.59706, -4.70473]]]]
26595 nameEn: "Papua New Guinea",
26596 groups: ["054", "009", "UN"],
26598 callingCodes: ["675"]
26601 type: "MultiPolygon",
26602 coordinates: [[[[141.03157, 2.12829], [140.99813, -6.3233], [140.85295, -6.72996], [140.90448, -6.85033], [141.01763, -6.90181], [141.01842, -9.35091], [141.88934, -9.36111], [142.19246, -9.15378], [142.48658, -9.36754], [143.29772, -9.33993], [143.87386, -9.02382], [145.2855, -9.62524], [156.73836, -14.50464], [154.74815, -7.33315], [155.60735, -6.92266], [155.69784, -6.92661], [155.92557, -6.84664], [156.03993, -6.65703], [156.03296, -6.55528], [160.43769, -4.17974], [141.03157, 2.12829]]]]
26611 nameEn: "Philippines",
26612 aliases: ["PI", "RP"],
26613 groups: ["035", "142", "UN"],
26614 callingCodes: ["63"]
26617 type: "MultiPolygon",
26618 coordinates: [[[[129.19694, 7.84182], [121.8109, 21.77688], [120.69238, 21.52331], [118.82252, 14.67191], [115.39742, 10.92666], [116.79524, 7.43869], [117.17735, 7.52841], [117.93857, 6.89845], [117.98544, 6.27477], [119.52945, 5.35672], [118.93936, 4.09009], [118.06469, 4.16638], [121.14448, 2.12444], [129.19694, 7.84182]]]]
26627 nameEn: "Pakistan",
26628 groups: ["034", "142", "UN"],
26630 callingCodes: ["92"]
26633 type: "MultiPolygon",
26634 coordinates: [[[[75.72737, 36.7529], [75.45562, 36.71971], [75.40481, 36.95382], [75.13839, 37.02622], [74.56453, 37.03023], [74.53739, 36.96224], [74.43389, 37.00977], [74.04856, 36.82648], [73.82685, 36.91421], [72.6323, 36.84601], [72.18135, 36.71838], [71.80267, 36.49924], [71.60491, 36.39429], [71.19505, 36.04134], [71.37969, 35.95865], [71.55273, 35.71483], [71.49917, 35.6267], [71.65435, 35.4479], [71.54294, 35.31037], [71.5541, 35.28776], [71.67495, 35.21262], [71.52938, 35.09023], [71.55273, 35.02615], [71.49917, 35.00478], [71.50329, 34.97328], [71.29472, 34.87728], [71.28356, 34.80882], [71.08718, 34.69034], [71.11602, 34.63047], [71.0089, 34.54568], [71.02401, 34.44835], [71.17662, 34.36769], [71.12815, 34.26619], [71.13078, 34.16503], [71.09453, 34.13524], [71.09307, 34.11961], [71.06933, 34.10564], [71.07345, 34.06242], [70.88119, 33.97933], [70.54336, 33.9463], [69.90203, 34.04194], [69.87307, 33.9689], [69.85671, 33.93719], [70.00503, 33.73528], [70.14236, 33.71701], [70.14785, 33.6553], [70.20141, 33.64387], [70.17062, 33.53535], [70.32775, 33.34496], [70.13686, 33.21064], [70.07369, 33.22557], [70.02563, 33.14282], [69.85259, 33.09451], [69.79766, 33.13247], [69.71526, 33.09911], [69.57656, 33.09911], [69.49004, 33.01509], [69.49854, 32.88843], [69.5436, 32.8768], [69.47082, 32.85834], [69.38018, 32.76601], [69.43649, 32.7302], [69.44747, 32.6678], [69.38155, 32.56601], [69.2868, 32.53938], [69.23599, 32.45946], [69.27932, 32.29119], [69.27032, 32.14141], [69.3225, 31.93186], [69.20577, 31.85957], [69.11514, 31.70782], [69.00939, 31.62249], [68.95995, 31.64822], [68.91078, 31.59687], [68.79997, 31.61665], [68.6956, 31.75687], [68.57475, 31.83158], [68.44222, 31.76446], [68.27605, 31.75863], [68.25614, 31.80357], [68.1655, 31.82691], [68.00071, 31.6564], [67.86887, 31.63536], [67.72056, 31.52304], [67.58323, 31.52772], [67.62374, 31.40473], [67.7748, 31.4188], [67.78854, 31.33203], [67.29964, 31.19586], [67.03323, 31.24519], [67.04147, 31.31561], [66.83273, 31.26867], [66.72561, 31.20526], [66.68166, 31.07597], [66.58175, 30.97532], [66.42645, 30.95309], [66.39194, 30.9408], [66.28413, 30.57001], [66.34869, 30.404], [66.23609, 30.06321], [66.36042, 29.9583], [66.24175, 29.85181], [65.04005, 29.53957], [64.62116, 29.58903], [64.19796, 29.50407], [64.12966, 29.39157], [63.5876, 29.50456], [62.47751, 29.40782], [60.87231, 29.86514], [61.31508, 29.38903], [61.53765, 29.00507], [61.65978, 28.77937], [61.93581, 28.55284], [62.40259, 28.42703], [62.59499, 28.24842], [62.79412, 28.28108], [62.7638, 28.02992], [62.84905, 27.47627], [62.79684, 27.34381], [62.80604, 27.22412], [63.19649, 27.25674], [63.32283, 27.14437], [63.25005, 27.08692], [63.25005, 26.84212], [63.18688, 26.83844], [63.1889, 26.65072], [62.77352, 26.64099], [62.31484, 26.528], [62.21304, 26.26601], [62.05117, 26.31647], [61.89391, 26.26251], [61.83831, 26.07249], [61.83968, 25.7538], [61.683, 25.66638], [61.6433, 25.27541], [61.46682, 24.57869], [68.11329, 23.53945], [68.20763, 23.85849], [68.39339, 23.96838], [68.74643, 23.97027], [68.7416, 24.31904], [68.90914, 24.33156], [68.97781, 24.26021], [69.07806, 24.29777], [69.19341, 24.25646], [69.29778, 24.28712], [69.59579, 24.29777], [69.73335, 24.17007], [70.03428, 24.172], [70.11712, 24.30915], [70.5667, 24.43787], [70.57906, 24.27774], [70.71502, 24.23517], [70.88393, 24.27398], [70.85784, 24.30903], [70.94985, 24.3791], [71.04461, 24.34657], [71.12838, 24.42662], [71.00341, 24.46038], [70.97594, 24.60904], [71.09405, 24.69017], [70.94002, 24.92843], [70.89148, 25.15064], [70.66695, 25.39314], [70.67382, 25.68186], [70.60378, 25.71898], [70.53649, 25.68928], [70.37444, 25.67443], [70.2687, 25.71156], [70.0985, 25.93238], [70.08193, 26.08094], [70.17532, 26.24118], [70.17532, 26.55362], [70.05584, 26.60398], [69.88555, 26.56836], [69.50904, 26.74892], [69.58519, 27.18109], [70.03136, 27.56627], [70.12502, 27.8057], [70.37307, 28.01208], [70.60927, 28.02178], [70.79054, 27.68423], [71.89921, 27.96035], [71.9244, 28.11555], [72.20329, 28.3869], [72.29495, 28.66367], [72.40402, 28.78283], [72.94272, 29.02487], [73.01337, 29.16422], [73.05886, 29.1878], [73.28094, 29.56646], [73.3962, 29.94707], [73.58665, 30.01848], [73.80299, 30.06969], [73.97225, 30.19829], [73.95736, 30.28466], [73.88993, 30.36305], [74.5616, 31.04153], [74.67971, 31.05479], [74.6852, 31.12771], [74.60006, 31.13711], [74.60281, 31.10419], [74.56023, 31.08303], [74.51629, 31.13829], [74.53223, 31.30321], [74.59773, 31.4136], [74.64713, 31.45605], [74.59319, 31.50197], [74.61517, 31.55698], [74.57498, 31.60382], [74.47771, 31.72227], [74.58907, 31.87824], [74.79919, 31.95983], [74.86236, 32.04485], [74.9269, 32.0658], [75.00793, 32.03786], [75.25649, 32.10187], [75.38046, 32.26836], [75.28259, 32.36556], [75.03265, 32.49538], [74.97634, 32.45367], [74.84725, 32.49075], [74.68362, 32.49298], [74.67431, 32.56676], [74.65251, 32.56416], [74.64424, 32.60985], [74.69542, 32.66792], [74.65345, 32.71225], [74.7113, 32.84219], [74.64675, 32.82604], [74.6289, 32.75561], [74.45312, 32.77755], [74.41467, 32.90563], [74.31227, 32.92795], [74.34875, 32.97823], [74.31854, 33.02891], [74.17571, 33.07495], [74.15374, 33.13477], [74.02144, 33.18908], [74.01366, 33.25199], [74.08782, 33.26232], [74.17983, 33.3679], [74.18121, 33.4745], [74.10115, 33.56392], [74.03576, 33.56718], [73.97367, 33.64061], [73.98968, 33.66155], [73.96423, 33.73071], [74.00891, 33.75437], [74.05898, 33.82089], [74.14001, 33.83002], [74.26086, 33.92237], [74.25262, 34.01577], [74.21554, 34.03853], [73.91341, 34.01235], [73.88732, 34.05105], [73.90677, 34.10504], [73.98208, 34.2522], [73.90517, 34.35317], [73.8475, 34.32935], [73.74862, 34.34183], [73.74999, 34.3781], [73.88732, 34.48911], [73.89419, 34.54568], [73.93951, 34.57169], [73.93401, 34.63386], [73.96423, 34.68244], [74.12897, 34.70073], [74.31239, 34.79626], [74.58083, 34.77386], [74.6663, 34.703], [75.01479, 34.64629], [75.38009, 34.55021], [75.75438, 34.51827], [76.04614, 34.67566], [76.15463, 34.6429], [76.47186, 34.78965], [76.67648, 34.76371], [76.74377, 34.84039], [76.74514, 34.92488], [76.87193, 34.96906], [76.99251, 34.93349], [77.11796, 35.05419], [76.93465, 35.39866], [76.85088, 35.39754], [76.75475, 35.52617], [76.77323, 35.66062], [76.50961, 35.8908], [76.33453, 35.84296], [76.14913, 35.82848], [76.15325, 35.9264], [75.93028, 36.13136], [76.00906, 36.17511], [76.0324, 36.41198], [75.92391, 36.56986], [75.72737, 36.7529]]]]
26644 groups: ["EU", "151", "150", "UN"],
26645 callingCodes: ["48"]
26648 type: "MultiPolygon",
26649 coordinates: [[[[18.57853, 55.25302], [14.20811, 54.12784], [14.22634, 53.9291], [14.20647, 53.91671], [14.18544, 53.91258], [14.20823, 53.90776], [14.21323, 53.8664], [14.27249, 53.74464], [14.26782, 53.69866], [14.2836, 53.67721], [14.27133, 53.66613], [14.28477, 53.65955], [14.2853, 53.63392], [14.31904, 53.61581], [14.30416, 53.55499], [14.3273, 53.50587], [14.35209, 53.49506], [14.4215, 53.27724], [14.44133, 53.27427], [14.45125, 53.26241], [14.40662, 53.21098], [14.37853, 53.20405], [14.36696, 53.16444], [14.38679, 53.13669], [14.35044, 53.05829], [14.25954, 53.00264], [14.14056, 52.95786], [14.15873, 52.87715], [14.12256, 52.84311], [14.13806, 52.82392], [14.22071, 52.81175], [14.61073, 52.59847], [14.6289, 52.57136], [14.60081, 52.53116], [14.63056, 52.48993], [14.54423, 52.42568], [14.55228, 52.35264], [14.56378, 52.33838], [14.58149, 52.28007], [14.70139, 52.25038], [14.71319, 52.22144], [14.68344, 52.19612], [14.70616, 52.16927], [14.67683, 52.13936], [14.6917, 52.10283], [14.72971, 52.09167], [14.76026, 52.06624], [14.71339, 52.00337], [14.70488, 51.97679], [14.7139, 51.95643], [14.71836, 51.95606], [14.72163, 51.95188], [14.7177, 51.94048], [14.70601, 51.92944], [14.6933, 51.9044], [14.6588, 51.88359], [14.59089, 51.83302], [14.60493, 51.80473], [14.64625, 51.79472], [14.66386, 51.73282], [14.69065, 51.70842], [14.75392, 51.67445], [14.75759, 51.62318], [14.7727, 51.61263], [14.71125, 51.56209], [14.73047, 51.54606], [14.72652, 51.53902], [14.73219, 51.52922], [14.94749, 51.47155], [14.9652, 51.44793], [14.96899, 51.38367], [14.98008, 51.33449], [15.04288, 51.28387], [15.01242, 51.21285], [15.0047, 51.16874], [14.99311, 51.16249], [14.99414, 51.15813], [15.00083, 51.14974], [14.99646, 51.14365], [14.99079, 51.14284], [14.99689, 51.12205], [14.98229, 51.11354], [14.97938, 51.07742], [14.95529, 51.04552], [14.92942, 50.99744], [14.89252, 50.94999], [14.89681, 50.9422], [14.81664, 50.88148], [14.82803, 50.86966], [14.99852, 50.86817], [15.01088, 50.97984], [14.96419, 50.99108], [15.02433, 51.0242], [15.03895, 51.0123], [15.06218, 51.02269], [15.10152, 51.01095], [15.11937, 50.99021], [15.16744, 51.01959], [15.1743, 50.9833], [15.2361, 50.99886], [15.27043, 50.97724], [15.2773, 50.8907], [15.36656, 50.83956], [15.3803, 50.77187], [15.43798, 50.80833], [15.73186, 50.73885], [15.81683, 50.75666], [15.87331, 50.67188], [15.97219, 50.69799], [16.0175, 50.63009], [15.98317, 50.61528], [16.02437, 50.60046], [16.10265, 50.66405], [16.20839, 50.63096], [16.23174, 50.67101], [16.33611, 50.66579], [16.44597, 50.58041], [16.34572, 50.49575], [16.31413, 50.50274], [16.19526, 50.43291], [16.21585, 50.40627], [16.22821, 50.41054], [16.28118, 50.36891], [16.30289, 50.38292], [16.36495, 50.37679], [16.3622, 50.34875], [16.39379, 50.3207], [16.42674, 50.32509], [16.56407, 50.21009], [16.55446, 50.16613], [16.63137, 50.1142], [16.7014, 50.09659], [16.8456, 50.20834], [16.98018, 50.24172], [17.00353, 50.21449], [17.02825, 50.23118], [16.99803, 50.25753], [17.02138, 50.27772], [16.99803, 50.30316], [16.94448, 50.31281], [16.90877, 50.38642], [16.85933, 50.41093], [16.89229, 50.45117], [17.1224, 50.39494], [17.14498, 50.38117], [17.19579, 50.38817], [17.19991, 50.3654], [17.27681, 50.32246], [17.34273, 50.32947], [17.34548, 50.2628], [17.3702, 50.28123], [17.58889, 50.27837], [17.67764, 50.28977], [17.69292, 50.32859], [17.74648, 50.29966], [17.72176, 50.25665], [17.76296, 50.23382], [17.70528, 50.18812], [17.59404, 50.16437], [17.66683, 50.10275], [17.6888, 50.12037], [17.7506, 50.07896], [17.77669, 50.02253], [17.86886, 49.97452], [18.00191, 50.01723], [18.04585, 50.01194], [18.04585, 50.03311], [18.00396, 50.04954], [18.03212, 50.06574], [18.07898, 50.04535], [18.10628, 50.00223], [18.20241, 49.99958], [18.21752, 49.97309], [18.27107, 49.96779], [18.27794, 49.93863], [18.31914, 49.91565], [18.33278, 49.92415], [18.33562, 49.94747], [18.41604, 49.93498], [18.53423, 49.89906], [18.54495, 49.9079], [18.54299, 49.92537], [18.57697, 49.91565], [18.57045, 49.87849], [18.60341, 49.86256], [18.57183, 49.83334], [18.61278, 49.7618], [18.61368, 49.75426], [18.62645, 49.75002], [18.62943, 49.74603], [18.62676, 49.71983], [18.69817, 49.70473], [18.72838, 49.68163], [18.80479, 49.6815], [18.84786, 49.5446], [18.84521, 49.51672], [18.94536, 49.52143], [18.97283, 49.49914], [18.9742, 49.39557], [19.18019, 49.41165], [19.25435, 49.53391], [19.36009, 49.53747], [19.37795, 49.574], [19.45348, 49.61583], [19.52626, 49.57311], [19.53313, 49.52856], [19.57845, 49.46077], [19.64162, 49.45184], [19.6375, 49.40897], [19.72127, 49.39288], [19.78581, 49.41701], [19.82237, 49.27806], [19.75286, 49.20751], [19.86409, 49.19316], [19.90529, 49.23532], [19.98494, 49.22904], [20.08238, 49.1813], [20.13738, 49.31685], [20.21977, 49.35265], [20.31453, 49.34817], [20.31728, 49.39914], [20.39939, 49.3896], [20.46422, 49.41612], [20.5631, 49.375], [20.61666, 49.41791], [20.72274, 49.41813], [20.77971, 49.35383], [20.9229, 49.29626], [20.98733, 49.30774], [21.09799, 49.37176], [21.041, 49.41791], [21.12477, 49.43666], [21.19756, 49.4054], [21.27858, 49.45988], [21.43376, 49.41433], [21.62328, 49.4447], [21.77983, 49.35443], [21.82927, 49.39467], [21.96385, 49.3437], [22.04427, 49.22136], [22.56155, 49.08865], [22.89122, 49.00725], [22.86336, 49.10513], [22.72009, 49.20288], [22.748, 49.32759], [22.69444, 49.49378], [22.64534, 49.53094], [22.78304, 49.65543], [22.80261, 49.69098], [22.83179, 49.69875], [22.99329, 49.84249], [23.28221, 50.0957], [23.67635, 50.33385], [23.71382, 50.38248], [23.79445, 50.40481], [23.99563, 50.41289], [24.03668, 50.44507], [24.07048, 50.5071], [24.0996, 50.60752], [24.0595, 50.71625], [23.95925, 50.79271], [23.99254, 50.83847], [24.0952, 50.83262], [24.14524, 50.86128], [24.04576, 50.90196], [23.92217, 51.00836], [23.90376, 51.07697], [23.80678, 51.18405], [23.63858, 51.32182], [23.69905, 51.40871], [23.62751, 51.50512], [23.56236, 51.53673], [23.57053, 51.55938], [23.53198, 51.74298], [23.62691, 51.78208], [23.61523, 51.92066], [23.68733, 51.9906], [23.64066, 52.07626], [23.61, 52.11264], [23.54314, 52.12148], [23.47859, 52.18215], [23.20071, 52.22848], [23.18196, 52.28812], [23.34141, 52.44845], [23.45112, 52.53774], [23.58296, 52.59868], [23.73615, 52.6149], [23.93763, 52.71332], [23.91805, 52.94016], [23.94689, 52.95919], [23.92184, 53.02079], [23.87548, 53.0831], [23.91393, 53.16469], [23.85657, 53.22923], [23.81995, 53.24131], [23.62004, 53.60942], [23.51284, 53.95052], [23.48261, 53.98855], [23.52702, 54.04622], [23.49196, 54.14764], [23.45223, 54.17775], [23.42418, 54.17911], [23.39525, 54.21672], [23.3494, 54.25155], [23.24656, 54.25701], [23.15938, 54.29894], [23.15526, 54.31076], [23.13905, 54.31567], [23.104, 54.29794], [23.04323, 54.31567], [23.05726, 54.34565], [22.99649, 54.35927], [23.00584, 54.38514], [22.83756, 54.40827], [22.79705, 54.36264], [21.41123, 54.32395], [20.63871, 54.3706], [19.8038, 54.44203], [19.64312, 54.45423], [18.57853, 55.25302]]]]
26657 wikidata: "Q34617",
26658 nameEn: "Saint Pierre and Miquelon",
26660 groups: ["Q1451600", "021", "003", "019", "UN"],
26661 callingCodes: ["508"]
26664 type: "MultiPolygon",
26665 coordinates: [[[[-56.72993, 46.65575], [-55.90758, 46.6223], [-56.27503, 47.39728], [-56.72993, 46.65575]]]]
26673 wikidata: "Q35672",
26674 nameEn: "Pitcairn Islands",
26676 groups: ["BOTS", "061", "009", "UN"],
26678 callingCodes: ["64"]
26681 type: "MultiPolygon",
26682 coordinates: [[[[-133.59543, -28.4709], [-122.0366, -24.55017], [-133.61511, -21.93325], [-133.59543, -28.4709]]]]
26691 nameEn: "Puerto Rico",
26692 aliases: ["US-PR"],
26694 groups: ["Q1352230", "029", "003", "419", "019", "UN"],
26695 roadSpeedUnit: "mph",
26696 callingCodes: ["1 787", "1 939"]
26699 type: "MultiPolygon",
26700 coordinates: [[[[-65.27974, 17.56928], [-65.02435, 18.73231], [-67.99519, 18.97186], [-68.23894, 17.84663], [-65.27974, 17.56928]]]]
26708 wikidata: "Q219060",
26709 nameEn: "Palestine"
26730 groups: ["057", "009", "UN"],
26731 roadSpeedUnit: "mph",
26732 callingCodes: ["680"]
26735 type: "MultiPolygon",
26736 coordinates: [[[[128.97621, 3.08804], [136.39296, 1.54187], [136.04605, 12.45908], [128.97621, 3.08804]]]]
26745 nameEn: "Paraguay",
26746 groups: ["005", "419", "019", "UN"],
26747 callingCodes: ["595"]
26750 type: "MultiPolygon",
26751 coordinates: [[[[-58.16225, -20.16193], [-58.23216, -19.80058], [-59.06965, -19.29148], [-60.00638, -19.2981], [-61.73723, -19.63958], [-61.93912, -20.10053], [-62.26883, -20.55311], [-62.2757, -21.06657], [-62.64455, -22.25091], [-62.51761, -22.37684], [-62.22768, -22.55807], [-61.9756, -23.0507], [-61.0782, -23.62932], [-60.99754, -23.80934], [-60.28163, -24.04436], [-60.03367, -24.00701], [-59.45482, -24.34787], [-59.33886, -24.49935], [-58.33055, -24.97099], [-58.25492, -24.92528], [-57.80821, -25.13863], [-57.57431, -25.47269], [-57.87176, -25.93604], [-58.1188, -26.16704], [-58.3198, -26.83443], [-58.65321, -27.14028], [-58.59549, -27.29973], [-58.04205, -27.2387], [-56.85337, -27.5165], [-56.18313, -27.29851], [-55.89195, -27.3467], [-55.74475, -27.44485], [-55.59094, -27.32444], [-55.62322, -27.1941], [-55.39611, -26.97679], [-55.25243, -26.93808], [-55.16948, -26.96068], [-55.06351, -26.80195], [-55.00584, -26.78754], [-54.80868, -26.55669], [-54.70732, -26.45099], [-54.69333, -26.37705], [-54.67359, -25.98607], [-54.60664, -25.9691], [-54.62063, -25.91213], [-54.59398, -25.59224], [-54.59509, -25.53696], [-54.60196, -25.48397], [-54.62033, -25.46026], [-54.4423, -25.13381], [-54.28207, -24.07305], [-54.32807, -24.01865], [-54.6238, -23.83078], [-55.02691, -23.97317], [-55.0518, -23.98666], [-55.12292, -23.99669], [-55.41784, -23.9657], [-55.44117, -23.9185], [-55.43585, -23.87157], [-55.5555, -23.28237], [-55.52288, -23.2595], [-55.5446, -23.22811], [-55.63849, -22.95122], [-55.62493, -22.62765], [-55.68742, -22.58407], [-55.6986, -22.56268], [-55.72366, -22.5519], [-55.741, -22.52018], [-55.74941, -22.46436], [-55.8331, -22.29008], [-56.23206, -22.25347], [-56.45893, -22.08072], [-56.5212, -22.11556], [-56.6508, -22.28387], [-57.98625, -22.09157], [-57.94642, -21.73799], [-57.88239, -21.6868], [-57.93492, -21.65505], [-57.84536, -20.93155], [-58.16225, -20.16193]]]]
26761 groups: ["145", "142", "UN"],
26762 callingCodes: ["974"]
26765 type: "MultiPolygon",
26766 coordinates: [[[[50.92992, 24.54396], [51.09638, 24.46907], [51.29972, 24.50747], [51.39468, 24.62785], [51.58834, 24.66608], [51.83108, 24.71675], [51.83682, 26.70231], [50.93865, 26.30758], [50.81266, 25.88946], [50.86149, 25.6965], [50.7801, 25.595], [50.80824, 25.54641], [50.57069, 25.57887], [50.8133, 24.74049], [50.92992, 24.54396]]]]
26774 wikidata: "Q17070",
26775 nameEn: "R\xE9union",
26777 groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
26778 callingCodes: ["262"]
26781 type: "MultiPolygon",
26782 coordinates: [[[[53.37984, -21.23941], [56.73473, -21.9174], [56.62373, -20.2711], [53.37984, -21.23941]]]]
26792 groups: ["EU", "151", "150", "UN"],
26793 callingCodes: ["40"]
26796 type: "MultiPolygon",
26797 coordinates: [[[[27.15622, 47.98538], [27.02985, 48.09083], [27.04118, 48.12522], [26.96119, 48.13003], [26.98042, 48.15752], [26.94265, 48.1969], [26.87708, 48.19919], [26.81161, 48.25049], [26.62823, 48.25804], [26.55202, 48.22445], [26.33504, 48.18418], [26.17711, 47.99246], [26.05901, 47.9897], [25.77723, 47.93919], [25.63878, 47.94924], [25.23778, 47.89403], [25.11144, 47.75203], [24.88896, 47.7234], [24.81893, 47.82031], [24.70632, 47.84428], [24.61994, 47.95062], [24.43578, 47.97131], [24.34926, 47.9244], [24.22566, 47.90231], [24.11281, 47.91487], [24.06466, 47.95317], [24.02999, 47.95087], [24.00801, 47.968], [23.98553, 47.96076], [23.96337, 47.96672], [23.94192, 47.94868], [23.89352, 47.94512], [23.8602, 47.9329], [23.80904, 47.98142], [23.75188, 47.99705], [23.66262, 47.98786], [23.63894, 48.00293], [23.5653, 48.00499], [23.52803, 48.01818], [23.4979, 47.96858], [23.33577, 48.0237], [23.27397, 48.08245], [23.15999, 48.12188], [23.1133, 48.08061], [23.08858, 48.00716], [23.0158, 47.99338], [22.92241, 48.02002], [22.94301, 47.96672], [22.89849, 47.95851], [22.77991, 47.87211], [22.76617, 47.8417], [22.67247, 47.7871], [22.46559, 47.76583], [22.41979, 47.7391], [22.31816, 47.76126], [22.00917, 47.50492], [22.03389, 47.42508], [22.01055, 47.37767], [21.94463, 47.38046], [21.78395, 47.11104], [21.648, 47.03902], [21.68645, 46.99595], [21.59581, 46.91628], [21.59307, 46.86935], [21.52028, 46.84118], [21.48935, 46.7577], [21.5151, 46.72147], [21.43926, 46.65109], [21.33214, 46.63035], [21.26929, 46.4993], [21.28061, 46.44941], [21.16872, 46.30118], [21.06572, 46.24897], [20.86797, 46.28884], [20.74574, 46.25467], [20.76085, 46.21002], [20.63863, 46.12728], [20.49718, 46.18721], [20.45377, 46.14405], [20.35573, 46.16629], [20.28324, 46.1438], [20.26068, 46.12332], [20.35862, 45.99356], [20.54818, 45.89939], [20.65645, 45.82801], [20.70069, 45.7493], [20.77416, 45.75601], [20.78446, 45.78522], [20.82364, 45.77738], [20.80361, 45.65875], [20.76798, 45.60969], [20.83321, 45.53567], [20.77217, 45.49788], [20.86026, 45.47295], [20.87948, 45.42743], [21.09894, 45.30144], [21.17612, 45.32566], [21.20392, 45.2677], [21.29398, 45.24148], [21.48278, 45.19557], [21.51299, 45.15345], [21.4505, 45.04294], [21.35855, 45.01941], [21.54938, 44.9327], [21.56328, 44.89502], [21.48202, 44.87199], [21.44013, 44.87613], [21.35643, 44.86364], [21.38802, 44.78133], [21.55007, 44.77304], [21.60019, 44.75208], [21.61942, 44.67059], [21.67504, 44.67107], [21.71692, 44.65349], [21.7795, 44.66165], [21.99364, 44.63395], [22.08016, 44.49844], [22.13234, 44.47444], [22.18315, 44.48179], [22.30844, 44.6619], [22.45301, 44.7194], [22.61917, 44.61489], [22.69196, 44.61587], [22.76749, 44.54446], [22.70981, 44.51852], [22.61368, 44.55719], [22.56493, 44.53419], [22.54021, 44.47836], [22.45436, 44.47258], [22.56012, 44.30712], [22.68166, 44.28206], [22.67173, 44.21564], [23.04988, 44.07694], [23.01674, 44.01946], [22.87873, 43.9844], [22.83753, 43.88055], [22.85314, 43.84452], [23.05288, 43.79494], [23.26772, 43.84843], [23.4507, 43.84936], [23.61687, 43.79289], [23.73978, 43.80627], [24.18149, 43.68218], [24.35364, 43.70211], [24.50264, 43.76314], [24.62281, 43.74082], [24.73542, 43.68523], [24.96682, 43.72693], [25.10718, 43.6831], [25.17144, 43.70261], [25.39528, 43.61866], [25.72792, 43.69263], [25.94911, 43.85745], [26.05584, 43.90925], [26.10115, 43.96908], [26.38764, 44.04356], [26.62712, 44.05698], [26.95141, 44.13555], [27.26845, 44.12602], [27.39757, 44.0141], [27.60834, 44.01206], [27.64542, 44.04958], [27.73468, 43.95326], [27.92008, 44.00761], [27.99558, 43.84193], [28.23293, 43.76], [29.24336, 43.70874], [30.04414, 45.08461], [29.69272, 45.19227], [29.65428, 45.25629], [29.68175, 45.26885], [29.59798, 45.38857], [29.42632, 45.44545], [29.24779, 45.43388], [28.96077, 45.33164], [28.94292, 45.28045], [28.81383, 45.3384], [28.78911, 45.24179], [28.71358, 45.22631], [28.5735, 45.24759], [28.34554, 45.32102], [28.28504, 45.43907], [28.21139, 45.46895], [28.18741, 45.47358], [28.08927, 45.6051], [28.16568, 45.6421], [28.13111, 45.92819], [28.08612, 46.01105], [28.13684, 46.18099], [28.10937, 46.22852], [28.19864, 46.31869], [28.18902, 46.35283], [28.25769, 46.43334], [28.22281, 46.50481], [28.24808, 46.64305], [28.12173, 46.82283], [28.09095, 46.97621], [27.81892, 47.1381], [27.73172, 47.29248], [27.68706, 47.28962], [27.60263, 47.32507], [27.55731, 47.46637], [27.47942, 47.48113], [27.3979, 47.59473], [27.32202, 47.64009], [27.25519, 47.71366], [27.29069, 47.73722], [27.1618, 47.92391], [27.15622, 47.98538]]]]
26807 groups: ["039", "150", "UN"],
26808 callingCodes: ["381"]
26811 type: "MultiPolygon",
26812 coordinates: [[[[19.66007, 46.19005], [19.56113, 46.16824], [19.52473, 46.1171], [19.28826, 45.99694], [19.14543, 45.9998], [19.10388, 46.04015], [19.0791, 45.96458], [19.01284, 45.96529], [18.99712, 45.93537], [18.81394, 45.91329], [18.85783, 45.85493], [18.90305, 45.71863], [18.96691, 45.66731], [18.88776, 45.57253], [18.94562, 45.53712], [19.07471, 45.53086], [19.08364, 45.48804], [18.99918, 45.49333], [18.97446, 45.37528], [19.10774, 45.29547], [19.28208, 45.23813], [19.41941, 45.23475], [19.43589, 45.17137], [19.19144, 45.17863], [19.14063, 45.12972], [19.07952, 45.14668], [19.1011, 45.01191], [19.05205, 44.97692], [19.15573, 44.95409], [19.06853, 44.89915], [19.02871, 44.92541], [18.98957, 44.90645], [19.01994, 44.85493], [19.18183, 44.92055], [19.36722, 44.88164], [19.32543, 44.74058], [19.26388, 44.65412], [19.16699, 44.52197], [19.13369, 44.52521], [19.12278, 44.50132], [19.14837, 44.45253], [19.14681, 44.41463], [19.11785, 44.40313], [19.10749, 44.39421], [19.10704, 44.38249], [19.10365, 44.37795], [19.10298, 44.36924], [19.11865, 44.36712], [19.1083, 44.3558], [19.11547, 44.34218], [19.13556, 44.338], [19.13332, 44.31492], [19.16741, 44.28648], [19.18328, 44.28383], [19.20508, 44.2917], [19.23306, 44.26097], [19.26945, 44.26957], [19.32464, 44.27185], [19.34773, 44.23244], [19.3588, 44.18353], [19.40927, 44.16722], [19.43905, 44.13088], [19.47338, 44.15034], [19.48386, 44.14332], [19.47321, 44.1193], [19.51167, 44.08158], [19.55999, 44.06894], [19.57467, 44.04716], [19.61991, 44.05254], [19.61836, 44.01464], [19.56498, 43.99922], [19.52515, 43.95573], [19.38439, 43.96611], [19.24363, 44.01502], [19.23465, 43.98764], [19.3986, 43.79668], [19.5176, 43.71403], [19.50455, 43.58385], [19.42696, 43.57987], [19.41941, 43.54056], [19.36653, 43.60921], [19.33426, 43.58833], [19.2553, 43.5938], [19.24774, 43.53061], [19.22807, 43.5264], [19.22229, 43.47926], [19.44315, 43.38846], [19.48171, 43.32644], [19.52962, 43.31623], [19.54598, 43.25158], [19.62661, 43.2286], [19.64063, 43.19027], [19.76918, 43.16044], [19.79255, 43.11951], [19.92576, 43.08539], [19.96549, 43.11098], [19.98887, 43.0538], [20.04729, 43.02732], [20.05431, 42.99571], [20.12325, 42.96237], [20.14896, 42.99058], [20.16415, 42.97177], [20.34528, 42.90676], [20.35692, 42.8335], [20.40594, 42.84853], [20.43734, 42.83157], [20.53484, 42.8885], [20.48692, 42.93208], [20.59929, 43.01067], [20.64557, 43.00826], [20.69515, 43.09641], [20.59929, 43.20492], [20.68688, 43.21335], [20.73811, 43.25068], [20.82145, 43.26769], [20.88685, 43.21697], [20.83727, 43.17842], [20.96287, 43.12416], [21.00749, 43.13984], [21.05378, 43.10707], [21.08952, 43.13471], [21.14465, 43.11089], [21.16734, 42.99694], [21.2041, 43.02277], [21.23877, 43.00848], [21.23534, 42.95523], [21.2719, 42.8994], [21.32974, 42.90424], [21.36941, 42.87397], [21.44047, 42.87276], [21.39045, 42.74888], [21.47498, 42.74695], [21.59154, 42.72643], [21.58755, 42.70418], [21.6626, 42.67813], [21.75025, 42.70125], [21.79413, 42.65923], [21.75672, 42.62695], [21.7327, 42.55041], [21.70522, 42.54176], [21.7035, 42.51899], [21.62556, 42.45106], [21.64209, 42.41081], [21.62887, 42.37664], [21.59029, 42.38042], [21.57021, 42.3647], [21.53467, 42.36809], [21.5264, 42.33634], [21.56772, 42.30946], [21.58992, 42.25915], [21.70111, 42.23789], [21.77176, 42.2648], [21.84654, 42.3247], [21.91595, 42.30392], [21.94405, 42.34669], [22.02908, 42.29848], [22.16384, 42.32103], [22.29605, 42.37477], [22.29275, 42.34913], [22.34773, 42.31725], [22.45919, 42.33822], [22.47498, 42.3915], [22.51961, 42.3991], [22.55669, 42.50144], [22.43983, 42.56851], [22.4997, 42.74144], [22.43309, 42.82057], [22.54302, 42.87774], [22.74826, 42.88701], [22.78397, 42.98253], [22.89521, 43.03625], [22.98104, 43.11199], [23.00806, 43.19279], [22.89727, 43.22417], [22.82036, 43.33665], [22.53397, 43.47225], [22.47582, 43.6558], [22.41043, 43.69566], [22.35558, 43.81281], [22.41449, 44.00514], [22.61688, 44.06534], [22.61711, 44.16938], [22.67173, 44.21564], [22.68166, 44.28206], [22.56012, 44.30712], [22.45436, 44.47258], [22.54021, 44.47836], [22.56493, 44.53419], [22.61368, 44.55719], [22.70981, 44.51852], [22.76749, 44.54446], [22.69196, 44.61587], [22.61917, 44.61489], [22.45301, 44.7194], [22.30844, 44.6619], [22.18315, 44.48179], [22.13234, 44.47444], [22.08016, 44.49844], [21.99364, 44.63395], [21.7795, 44.66165], [21.71692, 44.65349], [21.67504, 44.67107], [21.61942, 44.67059], [21.60019, 44.75208], [21.55007, 44.77304], [21.38802, 44.78133], [21.35643, 44.86364], [21.44013, 44.87613], [21.48202, 44.87199], [21.56328, 44.89502], [21.54938, 44.9327], [21.35855, 45.01941], [21.4505, 45.04294], [21.51299, 45.15345], [21.48278, 45.19557], [21.29398, 45.24148], [21.20392, 45.2677], [21.17612, 45.32566], [21.09894, 45.30144], [20.87948, 45.42743], [20.86026, 45.47295], [20.77217, 45.49788], [20.83321, 45.53567], [20.76798, 45.60969], [20.80361, 45.65875], [20.82364, 45.77738], [20.78446, 45.78522], [20.77416, 45.75601], [20.70069, 45.7493], [20.65645, 45.82801], [20.54818, 45.89939], [20.35862, 45.99356], [20.26068, 46.12332], [20.09713, 46.17315], [20.03533, 46.14509], [20.01816, 46.17696], [19.93508, 46.17553], [19.81491, 46.1313], [19.66007, 46.19005]]]]
26832 groups: ["014", "202", "002", "UN"],
26833 callingCodes: ["250"]
26836 type: "MultiPolygon",
26837 coordinates: [[[[30.47194, -1.0555], [30.35212, -1.06896], [30.16369, -1.34303], [29.912, -1.48269], [29.82657, -1.31187], [29.59061, -1.39016], [29.53062, -1.40499], [29.45038, -1.5054], [29.36322, -1.50887], [29.24323, -1.66826], [29.24458, -1.69663], [29.11847, -1.90576], [29.17562, -2.12278], [29.105, -2.27043], [29.00051, -2.29001], [28.95642, -2.37321], [28.89601, -2.37321], [28.86826, -2.41888], [28.86846, -2.44866], [28.89132, -2.47557], [28.89342, -2.49017], [28.88846, -2.50493], [28.87497, -2.50887], [28.86209, -2.5231], [28.86193, -2.53185], [28.87943, -2.55165], [28.89288, -2.55848], [28.90226, -2.62385], [28.89793, -2.66111], [28.94346, -2.69124], [29.00357, -2.70596], [29.04081, -2.7416], [29.0562, -2.58632], [29.32234, -2.6483], [29.36805, -2.82933], [29.88237, -2.75105], [29.95911, -2.33348], [30.14034, -2.43626], [30.42933, -2.31064], [30.54501, -2.41404], [30.83915, -2.35795], [30.89303, -2.08223], [30.80802, -1.91477], [30.84079, -1.64652], [30.71974, -1.43244], [30.57123, -1.33264], [30.50889, -1.16412], [30.45116, -1.10641], [30.47194, -1.0555]]]]
26846 nameEn: "Saudi Arabia",
26847 groups: ["145", "142", "UN"],
26848 callingCodes: ["966"]
26851 type: "MultiPolygon",
26852 coordinates: [[[[40.01521, 32.05667], [39.29903, 32.23259], [38.99233, 31.99721], [36.99791, 31.50081], [37.99354, 30.49998], [37.66395, 30.33245], [37.4971, 29.99949], [36.75083, 29.86903], [36.50005, 29.49696], [36.07081, 29.18469], [34.8812, 29.36878], [34.4454, 27.91479], [37.8565, 22.00903], [39.63762, 18.37348], [40.99158, 15.81743], [42.15205, 16.40211], [42.76801, 16.40371], [42.94625, 16.39721], [42.94351, 16.49467], [42.97215, 16.51093], [43.11601, 16.53166], [43.15274, 16.67248], [43.22066, 16.65179], [43.21325, 16.74416], [43.25857, 16.75304], [43.26303, 16.79479], [43.24801, 16.80613], [43.22956, 16.80613], [43.22012, 16.83932], [43.18338, 16.84852], [43.1398, 16.90696], [43.19328, 16.94703], [43.1813, 16.98438], [43.18233, 17.02673], [43.23967, 17.03428], [43.17787, 17.14717], [43.20156, 17.25901], [43.32653, 17.31179], [43.22533, 17.38343], [43.29185, 17.53224], [43.43005, 17.56148], [43.70631, 17.35762], [44.50126, 17.47475], [46.31018, 17.20464], [46.76494, 17.29151], [47.00571, 16.94765], [47.48245, 17.10808], [47.58351, 17.50366], [48.19996, 18.20584], [49.04884, 18.59899], [52.00311, 19.00083], [54.99756, 20.00083], [55.66469, 21.99658], [55.2137, 22.71065], [55.13599, 22.63334], [52.56622, 22.94341], [51.59617, 24.12041], [51.58871, 24.27256], [51.41644, 24.39615], [51.58834, 24.66608], [51.39468, 24.62785], [51.29972, 24.50747], [51.09638, 24.46907], [50.92992, 24.54396], [50.8133, 24.74049], [50.57069, 25.57887], [50.302, 25.87592], [50.26923, 26.08243], [50.38162, 26.53976], [50.71771, 26.73086], [50.37726, 27.89227], [49.98877, 27.87827], [49.00421, 28.81495], [48.42991, 28.53628], [47.70561, 28.5221], [47.59863, 28.66798], [47.58376, 28.83382], [47.46202, 29.0014], [46.5527, 29.10283], [46.42415, 29.05947], [44.72255, 29.19736], [42.97796, 30.48295], [42.97601, 30.72204], [40.01521, 32.05667]]]]
26861 nameEn: "Solomon Islands",
26862 groups: ["054", "009", "UN"],
26864 callingCodes: ["677"]
26867 type: "MultiPolygon",
26868 coordinates: [[[[172.71443, -12.01327], [160.43769, -4.17974], [156.03296, -6.55528], [156.03993, -6.65703], [155.92557, -6.84664], [155.69784, -6.92661], [155.60735, -6.92266], [154.74815, -7.33315], [156.73836, -14.50464], [172.71443, -12.01327]]]]
26877 nameEn: "Seychelles",
26878 groups: ["014", "202", "002", "UN"],
26880 callingCodes: ["248"]
26883 type: "MultiPolygon",
26884 coordinates: [[[[43.75112, -10.38913], [54.83239, -10.93575], [66.3222, 5.65313], [43.75112, -10.38913]]]]
26894 groups: ["015", "002", "UN"],
26895 callingCodes: ["249"]
26898 type: "MultiPolygon",
26899 coordinates: [[[[37.8565, 22.00903], [34.0765, 22.00501], [33.99686, 21.76784], [33.57251, 21.72406], [33.17563, 22.00405], [24.99885, 21.99535], [24.99794, 19.99661], [23.99715, 20.00038], [23.99539, 19.49944], [23.99997, 15.69575], [23.62785, 15.7804], [23.38812, 15.69649], [23.10792, 15.71297], [22.93201, 15.55107], [22.92579, 15.47007], [22.99584, 15.40105], [22.99584, 15.22989], [22.66115, 14.86308], [22.70474, 14.69149], [22.38562, 14.58907], [22.44944, 14.24986], [22.55997, 14.23024], [22.5553, 14.11704], [22.22995, 13.96754], [22.08674, 13.77863], [22.29689, 13.3731], [22.1599, 13.19281], [22.02914, 13.13976], [21.94819, 13.05637], [21.81432, 12.81362], [21.89371, 12.68001], [21.98711, 12.63292], [22.15679, 12.66634], [22.22684, 12.74682], [22.46345, 12.61925], [22.38873, 12.45514], [22.50548, 12.16769], [22.48369, 12.02766], [22.64092, 12.07485], [22.54907, 11.64372], [22.7997, 11.40424], [22.93124, 11.41645], [22.97249, 11.21955], [22.87758, 10.91915], [23.02221, 10.69235], [23.3128, 10.45214], [23.67164, 9.86923], [23.69155, 9.67566], [24.09319, 9.66572], [24.12744, 9.73784], [24.49389, 9.79962], [24.84653, 9.80643], [24.97739, 9.9081], [25.05688, 10.06776], [25.0918, 10.33718], [25.78141, 10.42599], [25.93163, 10.38159], [25.93241, 10.17941], [26.21338, 9.91545], [26.35815, 9.57946], [26.70685, 9.48735], [27.14427, 9.62858], [27.90704, 9.61323], [28.99983, 9.67155], [29.06988, 9.74826], [29.53844, 9.75133], [29.54, 10.07949], [29.94629, 10.29245], [30.00389, 10.28633], [30.53005, 9.95992], [30.82893, 9.71451], [30.84605, 9.7498], [31.28504, 9.75287], [31.77539, 10.28939], [31.99177, 10.65065], [32.46967, 11.04662], [32.39358, 11.18207], [32.39578, 11.70208], [32.10079, 11.95203], [32.73921, 11.95203], [32.73921, 12.22757], [33.25876, 12.22111], [33.13988, 11.43248], [33.26977, 10.83632], [33.24645, 10.77913], [33.52294, 10.64382], [33.66604, 10.44254], [33.80913, 10.32994], [33.90159, 10.17179], [33.96984, 10.15446], [33.99185, 9.99623], [33.96323, 9.80972], [33.9082, 9.762], [33.87958, 9.49937], [34.10229, 9.50238], [34.08717, 9.55243], [34.13186, 9.7492], [34.20484, 9.9033], [34.22718, 10.02506], [34.32102, 10.11599], [34.34783, 10.23914], [34.2823, 10.53508], [34.4372, 10.781], [34.59062, 10.89072], [34.77383, 10.74588], [34.77532, 10.69027], [34.86618, 10.74588], [34.86916, 10.78832], [34.97491, 10.86147], [34.97789, 10.91559], [34.93172, 10.95946], [35.01215, 11.19626], [34.95704, 11.24448], [35.09556, 11.56278], [35.05832, 11.71158], [35.11492, 11.85156], [35.24302, 11.91132], [35.70476, 12.67101], [36.01458, 12.72478], [36.14268, 12.70879], [36.16651, 12.88019], [36.13374, 12.92665], [36.24545, 13.36759], [36.38993, 13.56459], [36.48824, 13.83954], [36.44653, 13.95666], [36.54376, 14.25597], [36.44337, 15.14963], [36.54276, 15.23478], [36.69761, 15.75323], [36.76371, 15.80831], [36.92193, 16.23451], [36.99777, 17.07172], [37.42694, 17.04041], [37.50967, 17.32199], [38.13362, 17.53906], [38.37133, 17.66269], [38.45916, 17.87167], [38.57727, 17.98125], [39.63762, 18.37348], [37.8565, 22.00903]]]]
26909 groups: ["EU", "154", "150", "UN"],
26910 callingCodes: ["46"]
26913 type: "MultiPolygon",
26914 coordinates: [[[[24.15791, 65.85385], [23.90497, 66.15802], [23.71339, 66.21299], [23.64982, 66.30603], [23.67591, 66.3862], [23.63776, 66.43568], [23.85959, 66.56434], [23.89488, 66.772], [23.98059, 66.79585], [23.98563, 66.84149], [23.56214, 67.17038], [23.58735, 67.20752], [23.54701, 67.25435], [23.75372, 67.29914], [23.75372, 67.43688], [23.39577, 67.46974], [23.54701, 67.59306], [23.45627, 67.85297], [23.65793, 67.9497], [23.40081, 68.05545], [23.26469, 68.15134], [23.15377, 68.14759], [23.10336, 68.26551], [22.73028, 68.40881], [22.00429, 68.50692], [21.03001, 68.88969], [20.90649, 68.89696], [20.85104, 68.93142], [20.91658, 68.96764], [20.78802, 69.03087], [20.55258, 69.06069], [20.0695, 69.04469], [20.28444, 68.93283], [20.33435, 68.80174], [20.22027, 68.67246], [19.95647, 68.55546], [20.22027, 68.48759], [19.93508, 68.35911], [18.97255, 68.52416], [18.63032, 68.50849], [18.39503, 68.58672], [18.1241, 68.53721], [18.13836, 68.20874], [17.90787, 67.96537], [17.30416, 68.11591], [16.7409, 67.91037], [16.38441, 67.52923], [16.12774, 67.52106], [16.09922, 67.4364], [16.39154, 67.21653], [16.35589, 67.06419], [15.37197, 66.48217], [15.49318, 66.28509], [15.05113, 66.15572], [14.53778, 66.12399], [14.50926, 65.31786], [13.64276, 64.58402], [14.11117, 64.46674], [14.16051, 64.18725], [13.98222, 64.00953], [13.23411, 64.09087], [12.74105, 64.02171], [12.14928, 63.59373], [12.19919, 63.47935], [11.98529, 63.27487], [12.19919, 63.00104], [12.07085, 62.6297], [12.29187, 62.25699], [12.14746, 61.7147], [12.40595, 61.57226], [12.57707, 61.56547], [12.86939, 61.35427], [12.69115, 61.06584], [12.2277, 61.02442], [12.59133, 60.50559], [12.52003, 60.13846], [12.36317, 59.99259], [12.15641, 59.8926], [11.87121, 59.86039], [11.92112, 59.69531], [11.69297, 59.59442], [11.8213, 59.24985], [11.65732, 58.90177], [11.45199, 58.89604], [11.4601, 58.99022], [11.34459, 59.11672], [11.15367, 59.07862], [11.08911, 58.98745], [10.64958, 58.89391], [10.40861, 58.38489], [12.16597, 56.60205], [12.07466, 56.29488], [12.65312, 56.04345], [12.6372, 55.91371], [12.88472, 55.63369], [12.60345, 55.42675], [12.84405, 55.13257], [14.28399, 55.1553], [14.89259, 55.5623], [15.79951, 55.54655], [19.64795, 57.06466], [19.84909, 57.57876], [20.5104, 59.15546], [19.08191, 60.19152], [19.23413, 60.61414], [20.15877, 63.06556], [24.14112, 65.39731], [24.15107, 65.81427], [24.14798, 65.83466], [24.15791, 65.85385]]]]
26923 nameEn: "Singapore",
26924 groups: ["035", "142", "UN"],
26926 callingCodes: ["65"]
26929 type: "MultiPolygon",
26930 coordinates: [[[[104.00131, 1.42405], [103.93384, 1.42926], [103.89565, 1.42841], [103.86383, 1.46288], [103.81181, 1.47953], [103.76395, 1.45183], [103.74161, 1.4502], [103.7219, 1.46108], [103.67468, 1.43166], [103.62738, 1.35255], [103.56591, 1.19719], [103.66049, 1.18825], [103.74084, 1.12902], [104.03085, 1.26954], [104.12282, 1.27714], [104.08072, 1.35998], [104.09162, 1.39694], [104.08871, 1.42015], [104.07348, 1.43322], [104.04622, 1.44691], [104.02277, 1.4438], [104.00131, 1.42405]]]]
26938 wikidata: "Q192184",
26939 nameEn: "Saint Helena, Ascension and Tristan da Cunha",
26950 nameEn: "Slovenia",
26951 groups: ["EU", "039", "150", "UN"],
26952 callingCodes: ["386"]
26955 type: "MultiPolygon",
26956 coordinates: [[[[16.50139, 46.56684], [16.39217, 46.63673], [16.38594, 46.6549], [16.41863, 46.66238], [16.42641, 46.69228], [16.37816, 46.69975], [16.30966, 46.7787], [16.31303, 46.79838], [16.3408, 46.80641], [16.34547, 46.83836], [16.2941, 46.87137], [16.2365, 46.87775], [16.21892, 46.86961], [16.15711, 46.85434], [16.14365, 46.8547], [16.10983, 46.867], [16.05786, 46.83927], [15.99054, 46.82772], [15.99126, 46.78199], [15.98432, 46.74991], [15.99769, 46.7266], [16.02808, 46.71094], [16.04347, 46.68694], [16.04036, 46.6549], [15.99988, 46.67947], [15.98512, 46.68463], [15.94864, 46.68769], [15.87691, 46.7211], [15.8162, 46.71897], [15.78518, 46.70712], [15.76771, 46.69863], [15.73823, 46.70011], [15.72279, 46.69548], [15.69523, 46.69823], [15.67411, 46.70735], [15.6543, 46.70616], [15.6543, 46.69228], [15.6365, 46.6894], [15.63255, 46.68069], [15.62317, 46.67947], [15.59826, 46.68908], [15.54533, 46.66985], [15.55333, 46.64988], [15.54431, 46.6312], [15.46906, 46.61321], [15.45514, 46.63697], [15.41235, 46.65556], [15.23711, 46.63994], [15.14215, 46.66131], [15.01451, 46.641], [14.98024, 46.6009], [14.96002, 46.63459], [14.92283, 46.60848], [14.87129, 46.61], [14.86419, 46.59411], [14.83549, 46.56614], [14.81836, 46.51046], [14.72185, 46.49974], [14.66892, 46.44936], [14.5942, 46.43434], [14.56463, 46.37208], [14.52176, 46.42617], [14.45877, 46.41717], [14.42608, 46.44614], [14.314, 46.43327], [14.28326, 46.44315], [14.15989, 46.43327], [14.12097, 46.47724], [14.04002, 46.49117], [14.00422, 46.48474], [13.89837, 46.52331], [13.7148, 46.5222], [13.68684, 46.43881], [13.59777, 46.44137], [13.5763, 46.42613], [13.5763, 46.40915], [13.47019, 46.3621], [13.43418, 46.35992], [13.44808, 46.33507], [13.37671, 46.29668], [13.42218, 46.20758], [13.47587, 46.22725], [13.56114, 46.2054], [13.56682, 46.18703], [13.64451, 46.18966], [13.66472, 46.17392], [13.64053, 46.13587], [13.57072, 46.09022], [13.50104, 46.05986], [13.49568, 46.04839], [13.50998, 46.04498], [13.49702, 46.01832], [13.47474, 46.00546], [13.50104, 45.98078], [13.52963, 45.96588], [13.56759, 45.96991], [13.58903, 45.99009], [13.62074, 45.98388], [13.63458, 45.98947], [13.64307, 45.98326], [13.6329, 45.94894], [13.63815, 45.93607], [13.61931, 45.91782], [13.60857, 45.89907], [13.59565, 45.89446], [13.58644, 45.88173], [13.57563, 45.8425], [13.58858, 45.83503], [13.59784, 45.8072], [13.66986, 45.79955], [13.8235, 45.7176], [13.83332, 45.70855], [13.83422, 45.68703], [13.87933, 45.65207], [13.9191, 45.6322], [13.8695, 45.60835], [13.86771, 45.59898], [13.84106, 45.58185], [13.78445, 45.5825], [13.74587, 45.59811], [13.7198, 45.59352], [13.6076, 45.64761], [13.45644, 45.59464], [13.56979, 45.4895], [13.62902, 45.45898], [13.67398, 45.4436], [13.7785, 45.46787], [13.81742, 45.43729], [13.88124, 45.42637], [13.90771, 45.45149], [13.97309, 45.45258], [13.99488, 45.47551], [13.96063, 45.50825], [14.00578, 45.52352], [14.07116, 45.48752], [14.20348, 45.46896], [14.22371, 45.50388], [14.24239, 45.50607], [14.26611, 45.48239], [14.27681, 45.4902], [14.32487, 45.47142], [14.36693, 45.48642], [14.49769, 45.54424], [14.5008, 45.60852], [14.53816, 45.6205], [14.57397, 45.67165], [14.60977, 45.66403], [14.59576, 45.62812], [14.69694, 45.57366], [14.68605, 45.53006], [14.71718, 45.53442], [14.80124, 45.49515], [14.81992, 45.45913], [14.90554, 45.47769], [14.92266, 45.52788], [15.02385, 45.48533], [15.05187, 45.49079], [15.16862, 45.42309], [15.27758, 45.46678], [15.33051, 45.45258], [15.38188, 45.48752], [15.30249, 45.53224], [15.29837, 45.5841], [15.27747, 45.60504], [15.31027, 45.6303], [15.34695, 45.63382], [15.34214, 45.64702], [15.38952, 45.63682], [15.4057, 45.64727], [15.34919, 45.71623], [15.30872, 45.69014], [15.25423, 45.72275], [15.40836, 45.79491], [15.47531, 45.79802], [15.47325, 45.8253], [15.52234, 45.82195], [15.57952, 45.84953], [15.64185, 45.82915], [15.66662, 45.84085], [15.70411, 45.8465], [15.68232, 45.86819], [15.68383, 45.88867], [15.67967, 45.90455], [15.70636, 45.92116], [15.70327, 46.00015], [15.71246, 46.01196], [15.72977, 46.04682], [15.62317, 46.09103], [15.6083, 46.11992], [15.59909, 46.14761], [15.64904, 46.19229], [15.6434, 46.21396], [15.67395, 46.22478], [15.75436, 46.21969], [15.75479, 46.20336], [15.78817, 46.21719], [15.79284, 46.25811], [15.97965, 46.30652], [16.07616, 46.3463], [16.07314, 46.36458], [16.05065, 46.3833], [16.05281, 46.39141], [16.14859, 46.40547], [16.18824, 46.38282], [16.30233, 46.37837], [16.30162, 46.40437], [16.27329, 46.41467], [16.27398, 46.42875], [16.25124, 46.48067], [16.23961, 46.49653], [16.26759, 46.50566], [16.26733, 46.51505], [16.29793, 46.5121], [16.37193, 46.55008], [16.38771, 46.53608], [16.44036, 46.5171], [16.5007, 46.49644], [16.52604, 46.47831], [16.59527, 46.47524], [16.52604, 46.5051], [16.52885, 46.53303], [16.50139, 46.56684]]]]
26964 wikidata: "Q842829",
26965 nameEn: "Svalbard and Jan Mayen",
26976 nameEn: "Slovakia",
26977 groups: ["EU", "151", "150", "UN"],
26978 callingCodes: ["421"]
26981 type: "MultiPolygon",
26982 coordinates: [[[[19.82237, 49.27806], [19.78581, 49.41701], [19.72127, 49.39288], [19.6375, 49.40897], [19.64162, 49.45184], [19.57845, 49.46077], [19.53313, 49.52856], [19.52626, 49.57311], [19.45348, 49.61583], [19.37795, 49.574], [19.36009, 49.53747], [19.25435, 49.53391], [19.18019, 49.41165], [18.9742, 49.39557], [18.97283, 49.49914], [18.94536, 49.52143], [18.84521, 49.51672], [18.74761, 49.492], [18.67757, 49.50895], [18.6144, 49.49824], [18.57183, 49.51162], [18.53063, 49.49022], [18.54848, 49.47059], [18.44686, 49.39467], [18.4084, 49.40003], [18.4139, 49.36517], [18.36446, 49.3267], [18.18456, 49.28909], [18.15022, 49.24518], [18.1104, 49.08624], [18.06885, 49.03157], [17.91814, 49.01784], [17.87831, 48.92679], [17.77944, 48.92318], [17.73126, 48.87885], [17.7094, 48.86721], [17.5295, 48.81117], [17.45671, 48.85004], [17.3853, 48.80936], [17.29054, 48.85546], [17.19355, 48.87602], [17.11202, 48.82925], [17.00215, 48.70887], [16.93955, 48.60371], [16.94611, 48.53614], [16.85204, 48.44968], [16.8497, 48.38321], [16.83588, 48.3844], [16.83317, 48.38138], [16.84243, 48.35258], [16.90903, 48.32519], [16.89461, 48.31332], [16.97701, 48.17385], [17.02919, 48.13996], [17.05735, 48.14179], [17.09168, 48.09366], [17.07039, 48.0317], [17.16001, 48.00636], [17.23699, 48.02094], [17.71215, 47.7548], [18.02938, 47.75665], [18.29305, 47.73541], [18.56496, 47.76588], [18.66521, 47.76772], [18.74074, 47.8157], [18.8506, 47.82308], [18.76821, 47.87469], [18.76134, 47.97499], [18.82176, 48.04206], [19.01952, 48.07052], [19.23924, 48.0595], [19.28182, 48.08336], [19.47957, 48.09437], [19.52489, 48.19791], [19.63338, 48.25006], [19.92452, 48.1283], [20.24312, 48.2784], [20.29943, 48.26104], [20.5215, 48.53336], [20.83248, 48.5824], [21.11516, 48.49546], [21.44063, 48.58456], [21.6068, 48.50365], [21.67134, 48.3989], [21.72525, 48.34628], [21.8279, 48.33321], [21.83339, 48.36242], [22.14689, 48.4005], [22.16023, 48.56548], [22.21379, 48.6218], [22.34151, 48.68893], [22.42934, 48.92857], [22.48296, 48.99172], [22.54338, 49.01424], [22.56155, 49.08865], [22.04427, 49.22136], [21.96385, 49.3437], [21.82927, 49.39467], [21.77983, 49.35443], [21.62328, 49.4447], [21.43376, 49.41433], [21.27858, 49.45988], [21.19756, 49.4054], [21.12477, 49.43666], [21.041, 49.41791], [21.09799, 49.37176], [20.98733, 49.30774], [20.9229, 49.29626], [20.77971, 49.35383], [20.72274, 49.41813], [20.61666, 49.41791], [20.5631, 49.375], [20.46422, 49.41612], [20.39939, 49.3896], [20.31728, 49.39914], [20.31453, 49.34817], [20.21977, 49.35265], [20.13738, 49.31685], [20.08238, 49.1813], [19.98494, 49.22904], [19.90529, 49.23532], [19.86409, 49.19316], [19.75286, 49.20751], [19.82237, 49.27806]]]]
26991 nameEn: "Sierra Leone",
26992 groups: ["011", "202", "002", "UN"],
26993 callingCodes: ["232"]
26996 type: "MultiPolygon",
26997 coordinates: [[[[-10.27575, 8.48711], [-10.37257, 8.48941], [-10.54891, 8.31174], [-10.63934, 8.35326], [-10.70565, 8.29235], [-10.61422, 8.5314], [-10.47707, 8.67669], [-10.56197, 8.81225], [-10.5783, 9.06386], [-10.74484, 9.07998], [-10.6534, 9.29919], [-11.2118, 10.00098], [-11.89624, 9.99763], [-11.91023, 9.93927], [-12.12634, 9.87203], [-12.24262, 9.92386], [-12.47254, 9.86834], [-12.76788, 9.3133], [-12.94095, 9.26335], [-13.08953, 9.0409], [-13.18586, 9.0925], [-13.29911, 9.04245], [-14.36218, 8.64107], [-12.15048, 6.15992], [-11.50429, 6.92704], [-11.4027, 6.97746], [-11.29417, 7.21576], [-10.60422, 7.7739], [-10.60492, 8.04072], [-10.57523, 8.04829], [-10.51554, 8.1393], [-10.45023, 8.15627], [-10.35227, 8.15223], [-10.29839, 8.21283], [-10.31635, 8.28554], [-10.30084, 8.30008], [-10.27575, 8.48711]]]]
27006 nameEn: "San Marino",
27007 groups: ["039", "150", "UN"],
27008 callingCodes: ["378"]
27011 type: "MultiPolygon",
27012 coordinates: [[[[12.45648, 43.89369], [12.48771, 43.89706], [12.49429, 43.90973], [12.49247, 43.91774], [12.49724, 43.92248], [12.50269, 43.92363], [12.50496, 43.93017], [12.51553, 43.94096], [12.51427, 43.94897], [12.50655, 43.95796], [12.50875, 43.96198], [12.50622, 43.97131], [12.51109, 43.97201], [12.51064, 43.98165], [12.5154, 43.98508], [12.51463, 43.99122], [12.50678, 43.99113], [12.49406, 43.98492], [12.47853, 43.98052], [12.46205, 43.97463], [12.44684, 43.96597], [12.43662, 43.95698], [12.42005, 43.9578], [12.41414, 43.95273], [12.40415, 43.95485], [12.40506, 43.94325], [12.41165, 43.93769], [12.41551, 43.92984], [12.40733, 43.92379], [12.41233, 43.90956], [12.40935, 43.9024], [12.41641, 43.89991], [12.44184, 43.90498], [12.45648, 43.89369]]]]
27022 groups: ["011", "202", "002", "UN"],
27023 callingCodes: ["221"]
27026 type: "MultiPolygon",
27027 coordinates: [[[[-14.32144, 16.61495], [-15.00557, 16.64997], [-15.6509, 16.50315], [-16.27016, 16.51565], [-16.4429, 16.20605], [-16.44814, 16.09753], [-16.48967, 16.0496], [-16.50854, 16.09032], [-17.15288, 16.07139], [-18.35085, 14.63444], [-17.43598, 13.59273], [-15.47902, 13.58758], [-15.36504, 13.79313], [-14.93719, 13.80173], [-14.34721, 13.46578], [-13.8955, 13.59126], [-13.79409, 13.34472], [-14.36795, 13.23033], [-15.14917, 13.57989], [-15.26908, 13.37768], [-15.80478, 13.34832], [-15.80355, 13.16729], [-16.69343, 13.16791], [-16.74676, 13.06025], [-17.43966, 13.04579], [-17.4623, 11.92379], [-16.70562, 12.34803], [-16.38191, 12.36449], [-16.20591, 12.46157], [-15.67302, 12.42974], [-15.17582, 12.6847], [-13.70523, 12.68013], [-13.05296, 12.64003], [-13.06603, 12.49342], [-12.87336, 12.51892], [-12.35415, 12.32758], [-11.91331, 12.42008], [-11.46267, 12.44559], [-11.37536, 12.40788], [-11.39935, 12.97808], [-11.63025, 13.39174], [-11.83345, 13.33333], [-12.06897, 13.71049], [-11.93043, 13.84505], [-12.23936, 14.76324], [-13.11029, 15.52116], [-13.43135, 16.09022], [-13.80075, 16.13961], [-14.32144, 16.61495]]]]
27037 groups: ["014", "202", "002", "UN"],
27038 callingCodes: ["252"]
27041 type: "MultiPolygon",
27042 coordinates: [[[[51.12877, 12.56479], [43.90659, 12.3823], [42.95776, 10.98533], [42.69452, 10.62672], [42.87643, 10.18441], [43.0937, 9.90579], [43.23518, 9.84605], [43.32613, 9.59205], [44.19222, 8.93028], [46.99339, 7.9989], [47.92477, 8.00111], [47.97917, 8.00124], [44.98104, 4.91821], [44.02436, 4.9451], [43.40263, 4.79289], [43.04177, 4.57923], [42.97746, 4.44032], [42.84526, 4.28357], [42.55853, 4.20518], [42.07619, 4.17667], [41.89488, 3.97375], [41.31368, 3.14314], [40.98767, 2.82959], [41.00099, -0.83068], [41.56, -1.59812], [41.56362, -1.66375], [41.75542, -1.85308], [57.49095, 8.14549], [51.12877, 12.56479]]]]
27051 nameEn: "Suriname",
27052 groups: ["005", "419", "019", "UN"],
27054 callingCodes: ["597"]
27057 type: "MultiPolygon",
27058 coordinates: [[[[-54.26916, 5.26909], [-54.01877, 5.52789], [-54.01074, 5.68785], [-53.7094, 6.2264], [-56.84822, 6.73257], [-57.31629, 5.33714], [-57.22536, 5.15605], [-57.37442, 5.0208], [-57.8699, 4.89394], [-58.0307, 3.95513], [-57.35891, 3.32121], [-56.70519, 2.02964], [-56.55439, 2.02003], [-56.47045, 1.95135], [-55.99278, 1.83137], [-55.89863, 1.89861], [-55.92159, 2.05236], [-56.13054, 2.27723], [-55.96292, 2.53188], [-55.71493, 2.40342], [-55.01919, 2.564], [-54.6084, 2.32856], [-54.42864, 2.42442], [-54.28534, 2.67798], [-53.9849, 3.58697], [-53.98914, 3.627], [-54.05128, 3.63557], [-54.19367, 3.84387], [-54.38444, 4.13222], [-54.4717, 4.91964], [-54.26916, 5.26909]]]]
27067 nameEn: "South Sudan",
27068 groups: ["014", "202", "002", "UN"],
27069 callingCodes: ["211"]
27072 type: "MultiPolygon",
27073 coordinates: [[[[34.10229, 9.50238], [33.87958, 9.49937], [33.9082, 9.762], [33.96323, 9.80972], [33.99185, 9.99623], [33.96984, 10.15446], [33.90159, 10.17179], [33.80913, 10.32994], [33.66604, 10.44254], [33.52294, 10.64382], [33.24645, 10.77913], [33.26977, 10.83632], [33.13988, 11.43248], [33.25876, 12.22111], [32.73921, 12.22757], [32.73921, 11.95203], [32.10079, 11.95203], [32.39578, 11.70208], [32.39358, 11.18207], [32.46967, 11.04662], [31.99177, 10.65065], [31.77539, 10.28939], [31.28504, 9.75287], [30.84605, 9.7498], [30.82893, 9.71451], [30.53005, 9.95992], [30.00389, 10.28633], [29.94629, 10.29245], [29.54, 10.07949], [29.53844, 9.75133], [29.06988, 9.74826], [28.99983, 9.67155], [27.90704, 9.61323], [27.14427, 9.62858], [26.70685, 9.48735], [26.35815, 9.57946], [26.21338, 9.91545], [25.93241, 10.17941], [25.93163, 10.38159], [25.78141, 10.42599], [25.0918, 10.33718], [25.05688, 10.06776], [24.97739, 9.9081], [24.84653, 9.80643], [24.49389, 9.79962], [24.12744, 9.73784], [24.09319, 9.66572], [23.69155, 9.67566], [23.62179, 9.53823], [23.64981, 9.44303], [23.64358, 9.28637], [23.56263, 9.19418], [23.4848, 9.16959], [23.44744, 8.99128], [23.59065, 8.99743], [23.51905, 8.71749], [24.25691, 8.69288], [24.13238, 8.36959], [24.35965, 8.26177], [24.85156, 8.16933], [24.98855, 7.96588], [25.25319, 7.8487], [25.29214, 7.66675], [25.20649, 7.61115], [25.20337, 7.50312], [25.35281, 7.42595], [25.37461, 7.33024], [25.90076, 7.09549], [26.38022, 6.63493], [26.32729, 6.36272], [26.58259, 6.1987], [26.51721, 6.09655], [27.22705, 5.71254], [27.22705, 5.62889], [27.28621, 5.56382], [27.23017, 5.37167], [27.26886, 5.25876], [27.44012, 5.07349], [27.56656, 4.89375], [27.65462, 4.89375], [27.76469, 4.79284], [27.79551, 4.59976], [28.20719, 4.35614], [28.6651, 4.42638], [28.8126, 4.48784], [29.03054, 4.48784], [29.22207, 4.34297], [29.43341, 4.50101], [29.49726, 4.7007], [29.82087, 4.56246], [29.79666, 4.37809], [30.06964, 4.13221], [30.1621, 4.10586], [30.22374, 3.93896], [30.27658, 3.95653], [30.47691, 3.83353], [30.55396, 3.84451], [30.57378, 3.74567], [30.56277, 3.62703], [30.78512, 3.67097], [30.80713, 3.60506], [30.85997, 3.5743], [30.85153, 3.48867], [30.97601, 3.693], [31.16666, 3.79853], [31.29476, 3.8015], [31.50478, 3.67814], [31.50776, 3.63652], [31.72075, 3.74354], [31.81459, 3.82083], [31.86821, 3.78664], [31.96205, 3.6499], [31.95907, 3.57408], [32.05187, 3.589], [32.08491, 3.56287], [32.08866, 3.53543], [32.19888, 3.50867], [32.20782, 3.6053], [32.41337, 3.748], [32.72021, 3.77327], [32.89746, 3.81339], [33.02852, 3.89296], [33.18356, 3.77812], [33.51264, 3.75068], [33.9873, 4.23316], [34.47601, 4.72162], [35.34151, 5.02364], [35.30992, 4.90402], [35.47843, 4.91872], [35.42366, 4.76969], [35.51424, 4.61643], [35.9419, 4.61933], [35.82118, 4.77382], [35.81968, 5.10757], [35.8576, 5.33413], [35.50792, 5.42431], [35.29938, 5.34042], [35.31188, 5.50106], [35.13058, 5.62118], [35.12611, 5.68937], [35.00546, 5.89387], [34.96227, 6.26415], [35.01738, 6.46991], [34.87736, 6.60161], [34.77459, 6.5957], [34.65096, 6.72589], [34.53776, 6.74808], [34.53925, 6.82794], [34.47669, 6.91076], [34.35753, 6.91963], [34.19369, 7.04382], [34.19369, 7.12807], [34.01495, 7.25664], [34.03878, 7.27437], [34.02984, 7.36449], [33.87642, 7.5491], [33.71407, 7.65983], [33.44745, 7.7543], [33.32531, 7.71297], [33.24637, 7.77939], [33.04944, 7.78989], [33.0006, 7.90333], [33.08401, 8.05822], [33.18083, 8.13047], [33.1853, 8.29264], [33.19721, 8.40317], [33.3119, 8.45474], [33.54575, 8.47094], [33.66938, 8.44442], [33.71407, 8.3678], [33.87195, 8.41938], [33.89579, 8.4842], [34.01346, 8.50041], [34.14453, 8.60204], [34.14304, 9.04654], [34.10229, 9.50238]]]]
27082 nameEn: "S\xE3o Tom\xE9 and Principe",
27083 groups: ["017", "202", "002", "UN"],
27084 callingCodes: ["239"]
27087 type: "MultiPolygon",
27088 coordinates: [[[[4.34149, 1.91417], [6.6507, -0.28606], [7.9035, 1.92304], [4.34149, 1.91417]]]]
27097 nameEn: "El Salvador",
27098 groups: ["013", "003", "419", "019", "UN"],
27099 callingCodes: ["503"]
27102 type: "MultiPolygon",
27103 coordinates: [[[[-89.34776, 14.43013], [-89.39028, 14.44561], [-89.57441, 14.41637], [-89.58814, 14.33165], [-89.50614, 14.26084], [-89.52397, 14.22628], [-89.61844, 14.21937], [-89.70756, 14.1537], [-89.75569, 14.07073], [-89.73251, 14.04133], [-89.76103, 14.02923], [-89.81807, 14.07073], [-89.88937, 14.0396], [-90.10505, 13.85104], [-90.11344, 13.73679], [-90.55276, 12.8866], [-88.11443, 12.63306], [-87.7346, 13.13228], [-87.55124, 13.12523], [-87.69751, 13.25228], [-87.73714, 13.32715], [-87.80177, 13.35689], [-87.84675, 13.41078], [-87.83467, 13.44655], [-87.77354, 13.45767], [-87.73841, 13.44169], [-87.72115, 13.46083], [-87.71657, 13.50577], [-87.78148, 13.52906], [-87.73106, 13.75443], [-87.68821, 13.80829], [-87.7966, 13.91353], [-88.00331, 13.86948], [-88.07641, 13.98447], [-88.23018, 13.99915], [-88.25791, 13.91108], [-88.48982, 13.86458], [-88.49738, 13.97224], [-88.70661, 14.04317], [-88.73182, 14.10919], [-88.815, 14.11652], [-88.85785, 14.17763], [-88.94608, 14.20207], [-89.04187, 14.33644], [-89.34776, 14.43013]]]]
27111 wikidata: "Q26273",
27112 nameEn: "Sint Maarten",
27113 aliases: ["NL-SX"],
27115 groups: ["Q1451600", "029", "003", "419", "019", "UN"],
27116 callingCodes: ["1 721"]
27119 type: "MultiPolygon",
27120 coordinates: [[[[-63.33064, 17.9615], [-63.1055, 17.86651], [-62.93924, 18.02904], [-63.02323, 18.05757], [-63.04039, 18.05619], [-63.0579, 18.06614], [-63.07759, 18.04943], [-63.09686, 18.04608], [-63.11042, 18.05339], [-63.13502, 18.05445], [-63.33064, 17.9615]]]]
27130 groups: ["145", "142", "UN"],
27131 callingCodes: ["963"]
27134 type: "MultiPolygon",
27135 coordinates: [[[[42.23683, 37.2863], [42.21548, 37.28026], [42.20454, 37.28715], [42.22381, 37.30238], [42.22257, 37.31395], [42.2112, 37.32491], [42.19301, 37.31323], [42.18225, 37.28569], [42.00894, 37.17209], [41.515, 37.08084], [41.21937, 37.07665], [40.90856, 37.13147], [40.69136, 37.0996], [39.81589, 36.75538], [39.21538, 36.66834], [39.03217, 36.70911], [38.74042, 36.70629], [38.55908, 36.84429], [38.38859, 36.90064], [38.21064, 36.91842], [37.81974, 36.76055], [37.68048, 36.75065], [37.49103, 36.66904], [37.47253, 36.63243], [37.21988, 36.6736], [37.16177, 36.66069], [37.10894, 36.6704], [37.08279, 36.63495], [37.02088, 36.66422], [37.01647, 36.69512], [37.04619, 36.71101], [37.04399, 36.73483], [36.99886, 36.74012], [36.99557, 36.75997], [36.66727, 36.82901], [36.61581, 36.74629], [36.62681, 36.71189], [36.57398, 36.65186], [36.58829, 36.58295], [36.54206, 36.49539], [36.6081, 36.33772], [36.65653, 36.33861], [36.68672, 36.23677], [36.6125, 36.22592], [36.50463, 36.2419], [36.4617, 36.20461], [36.39206, 36.22088], [36.37474, 36.01163], [36.33956, 35.98687], [36.30099, 36.00985], [36.28338, 36.00273], [36.29769, 35.96086], [36.27678, 35.94839], [36.25366, 35.96264], [36.19973, 35.95195], [36.17441, 35.92076], [36.1623, 35.80925], [36.14029, 35.81015], [36.13919, 35.83692], [36.11827, 35.85923], [35.99829, 35.88242], [36.01844, 35.92403], [36.00514, 35.94113], [35.98499, 35.94107], [35.931, 35.92109], [35.51152, 36.10954], [35.48515, 34.70851], [35.97386, 34.63322], [35.98718, 34.64977], [36.29165, 34.62991], [36.32399, 34.69334], [36.35135, 34.68516], [36.35384, 34.65447], [36.42941, 34.62505], [36.46003, 34.6378], [36.45299, 34.59438], [36.41429, 34.61175], [36.39846, 34.55672], [36.3369, 34.52629], [36.34745, 34.5002], [36.4442, 34.50165], [36.46179, 34.46541], [36.55853, 34.41609], [36.53039, 34.3798], [36.56556, 34.31881], [36.60778, 34.31009], [36.58667, 34.27667], [36.59195, 34.2316], [36.62537, 34.20251], [36.5128, 34.09916], [36.50576, 34.05982], [36.41078, 34.05253], [36.28589, 33.91981], [36.38263, 33.86579], [36.3967, 33.83365], [36.14517, 33.85118], [36.06778, 33.82927], [35.9341, 33.6596], [36.05723, 33.57904], [35.94465, 33.52774], [35.94816, 33.47886], [35.88668, 33.43183], [35.82577, 33.40479], [35.81324, 33.36354], [35.77477, 33.33609], [35.813, 33.3172], [35.77513, 33.27342], [35.81295, 33.24841], [35.81647, 33.2028], [35.83846, 33.19397], [35.84285, 33.16673], [35.81911, 33.1336], [35.81911, 33.11077], [35.84802, 33.1031], [35.87188, 32.98028], [35.89298, 32.9456], [35.87012, 32.91976], [35.84021, 32.8725], [35.83758, 32.82817], [35.78745, 32.77938], [35.75983, 32.74803], [35.88405, 32.71321], [35.93307, 32.71966], [35.96633, 32.66237], [36.02239, 32.65911], [36.08074, 32.51463], [36.20379, 32.52751], [36.20875, 32.49529], [36.23948, 32.50108], [36.40959, 32.37908], [36.83946, 32.31293], [38.79171, 33.37328], [40.64314, 34.31604], [40.97676, 34.39788], [41.12388, 34.65742], [41.2345, 34.80049], [41.21654, 35.1508], [41.26569, 35.42708], [41.38184, 35.62502], [41.37027, 35.84095], [41.2564, 36.06012], [41.28864, 36.35368], [41.40058, 36.52502], [41.81736, 36.58782], [42.36697, 37.0627], [42.35724, 37.10998], [42.32313, 37.17814], [42.34735, 37.22548], [42.2824, 37.2798], [42.26039, 37.27017], [42.23683, 37.2863]]]]
27144 nameEn: "Eswatini",
27145 aliases: ["Swaziland"],
27146 groups: ["018", "202", "002", "UN"],
27148 callingCodes: ["268"]
27151 type: "MultiPolygon",
27152 coordinates: [[[[31.86881, -25.99973], [31.4175, -25.71886], [31.31237, -25.7431], [31.13073, -25.91558], [30.95819, -26.26303], [30.78927, -26.48271], [30.81101, -26.84722], [30.88826, -26.79622], [30.97757, -26.92706], [30.96088, -27.0245], [31.15027, -27.20151], [31.49834, -27.31549], [31.97592, -27.31675], [31.97463, -27.11057], [32.00893, -26.8096], [32.09664, -26.80721], [32.13315, -26.84345], [32.13409, -26.5317], [32.07352, -26.40185], [32.10435, -26.15656], [32.08599, -26.00978], [32.00916, -25.999], [31.974, -25.95387], [31.86881, -25.99973]]]]
27159 wikidata: "Q220982",
27160 nameEn: "Tristan da Cunha",
27161 aliases: ["SH-TA"],
27163 groups: ["SH", "BOTS", "011", "202", "002", "UN"],
27164 isoStatus: "excRes",
27166 roadSpeedUnit: "mph",
27167 roadHeightUnit: "ft",
27168 callingCodes: ["290 8", "44 20"]
27171 type: "MultiPolygon",
27172 coordinates: [[[[-13.38232, -34.07258], [-16.67337, -41.9188], [-5.88482, -41.4829], [-13.38232, -34.07258]]]]
27180 wikidata: "Q18221",
27181 nameEn: "Turks and Caicos Islands",
27183 groups: ["BOTS", "029", "003", "419", "019", "UN"],
27185 roadSpeedUnit: "mph",
27186 roadHeightUnit: "ft",
27187 callingCodes: ["1 649"]
27190 type: "MultiPolygon",
27191 coordinates: [[[[-71.70065, 25.7637], [-72.98446, 20.4801], [-69.80718, 21.35956], [-71.70065, 25.7637]]]]
27201 groups: ["017", "202", "002", "UN"],
27202 callingCodes: ["235"]
27205 type: "MultiPolygon",
27206 coordinates: [[[[23.99539, 19.49944], [15.99566, 23.49639], [14.99751, 23.00539], [15.19692, 21.99339], [15.20213, 21.49365], [15.28332, 21.44557], [15.62515, 20.95395], [15.57248, 20.92138], [15.55382, 20.86507], [15.56004, 20.79488], [15.59841, 20.74039], [15.6721, 20.70069], [15.99632, 20.35364], [15.75098, 19.93002], [15.6032, 18.77402], [15.50373, 16.89649], [14.37425, 15.72591], [13.86301, 15.04043], [13.78991, 14.87519], [13.809, 14.72915], [13.67878, 14.64013], [13.68573, 14.55276], [13.48259, 14.46704], [13.47559, 14.40881], [13.6302, 13.71094], [14.08251, 13.0797], [14.46881, 13.08259], [14.56101, 12.91036], [14.55058, 12.78256], [14.83314, 12.62963], [14.90827, 12.3269], [14.89019, 12.16593], [14.96952, 12.0925], [15.00146, 12.1223], [15.0349, 12.10698], [15.05786, 12.0608], [15.04808, 11.8731], [15.11579, 11.79313], [15.06595, 11.71126], [15.13149, 11.5537], [15.0585, 11.40481], [15.10021, 11.04101], [15.04957, 11.02347], [15.09127, 10.87431], [15.06737, 10.80921], [15.15532, 10.62846], [15.14936, 10.53915], [15.23724, 10.47764], [15.30874, 10.31063], [15.50535, 10.1098], [15.68761, 9.99344], [15.41408, 9.92876], [15.24618, 9.99246], [15.14043, 9.99246], [15.05999, 9.94845], [14.95722, 9.97926], [14.80082, 9.93818], [14.4673, 10.00264], [14.20411, 10.00055], [14.1317, 9.82413], [14.01793, 9.73169], [13.97544, 9.6365], [14.37094, 9.2954], [14.35707, 9.19611], [14.83566, 8.80557], [15.09484, 8.65982], [15.20426, 8.50892], [15.50743, 7.79302], [15.59272, 7.7696], [15.56964, 7.58936], [15.49743, 7.52179], [15.73118, 7.52006], [15.79942, 7.44149], [16.40703, 7.68809], [16.41583, 7.77971], [16.58315, 7.88657], [16.59415, 7.76444], [16.658, 7.75353], [16.6668, 7.67281], [16.8143, 7.53971], [17.67288, 7.98905], [17.93926, 7.95853], [18.02731, 8.01085], [18.6085, 8.05009], [18.64153, 8.08714], [18.62612, 8.14163], [18.67455, 8.22226], [18.79783, 8.25929], [19.11044, 8.68172], [18.86388, 8.87971], [19.06421, 9.00367], [20.36748, 9.11019], [20.82979, 9.44696], [21.26348, 9.97642], [21.34934, 9.95907], [21.52766, 10.2105], [21.63553, 10.217], [21.71479, 10.29932], [21.72139, 10.64136], [22.45889, 11.00246], [22.87758, 10.91915], [22.97249, 11.21955], [22.93124, 11.41645], [22.7997, 11.40424], [22.54907, 11.64372], [22.64092, 12.07485], [22.48369, 12.02766], [22.50548, 12.16769], [22.38873, 12.45514], [22.46345, 12.61925], [22.22684, 12.74682], [22.15679, 12.66634], [21.98711, 12.63292], [21.89371, 12.68001], [21.81432, 12.81362], [21.94819, 13.05637], [22.02914, 13.13976], [22.1599, 13.19281], [22.29689, 13.3731], [22.08674, 13.77863], [22.22995, 13.96754], [22.5553, 14.11704], [22.55997, 14.23024], [22.44944, 14.24986], [22.38562, 14.58907], [22.70474, 14.69149], [22.66115, 14.86308], [22.99584, 15.22989], [22.99584, 15.40105], [22.92579, 15.47007], [22.93201, 15.55107], [23.10792, 15.71297], [23.38812, 15.69649], [23.62785, 15.7804], [23.99997, 15.69575], [23.99539, 19.49944]]]]
27214 wikidata: "Q129003",
27215 nameEn: "French Southern Territories",
27227 groups: ["011", "202", "002", "UN"],
27228 callingCodes: ["228"]
27231 type: "MultiPolygon",
27232 coordinates: [[[[0.50388, 11.01011], [-0.13493, 11.14075], [-0.14462, 11.10811], [-0.05733, 11.08628], [-0.0275, 11.11202], [-514e-5, 11.10763], [342e-5, 11.08317], [0.02395, 11.06229], [0.03355, 10.9807], [-63e-4, 10.96417], [-908e-5, 10.91644], [-0.02685, 10.8783], [-0.0228, 10.81916], [-0.07183, 10.76794], [-0.07327, 10.71845], [-0.09141, 10.7147], [-0.05945, 10.63458], [0.12886, 10.53149], [0.18846, 10.4096], [0.29453, 10.41546], [0.33028, 10.30408], [0.39584, 10.31112], [0.35293, 10.09412], [0.41371, 10.06361], [0.41252, 10.02018], [0.36366, 10.03309], [0.32075, 9.72781], [0.34816, 9.71607], [0.34816, 9.66907], [0.32313, 9.6491], [0.28261, 9.69022], [0.26712, 9.66437], [0.29334, 9.59387], [0.36008, 9.6256], [0.38153, 9.58682], [0.23851, 9.57389], [0.2409, 9.52335], [0.30406, 9.521], [0.31241, 9.50337], [0.2254, 9.47869], [0.25758, 9.42696], [0.33148, 9.44812], [0.36485, 9.49749], [0.49118, 9.48339], [0.56388, 9.40697], [0.45424, 9.04581], [0.52455, 8.87746], [0.37319, 8.75262], [0.47211, 8.59945], [0.64731, 8.48866], [0.73432, 8.29529], [0.63897, 8.25873], [0.5913, 8.19622], [0.61156, 8.18324], [0.6056, 8.13959], [0.58891, 8.12779], [0.62943, 7.85751], [0.58295, 7.62368], [0.51979, 7.58706], [0.52455, 7.45354], [0.57223, 7.39326], [0.62943, 7.41099], [0.65327, 7.31643], [0.59606, 7.01252], [0.52217, 6.9723], [0.52098, 6.94391], [0.56508, 6.92971], [0.52853, 6.82921], [0.57406, 6.80348], [0.58176, 6.76049], [0.6497, 6.73682], [0.63659, 6.63857], [0.74862, 6.56517], [0.71048, 6.53083], [0.89283, 6.33779], [0.99652, 6.33779], [1.03108, 6.24064], [1.05969, 6.22998], [1.09187, 6.17074], [1.19966, 6.17069], [1.19771, 6.11522], [1.27574, 5.93551], [1.67336, 6.02702], [1.62913, 6.24075], [1.79826, 6.28221], [1.76906, 6.43189], [1.58105, 6.68619], [1.61812, 6.74843], [1.55877, 6.99737], [1.64249, 6.99562], [1.61838, 9.0527], [1.5649, 9.16941], [1.41746, 9.3226], [1.33675, 9.54765], [1.36624, 9.5951], [1.35507, 9.99525], [0.77666, 10.37665], [0.80358, 10.71459], [0.8804, 10.803], [0.91245, 10.99597], [0.66104, 10.99964], [0.4958, 10.93269], [0.50521, 10.98035], [0.48852, 10.98561], [0.50388, 11.01011]]]]
27241 nameEn: "Thailand",
27242 groups: ["035", "142", "UN"],
27244 callingCodes: ["66"]
27247 type: "MultiPolygon",
27248 coordinates: [[[[100.08404, 20.36626], [99.95721, 20.46301], [99.91616, 20.44986], [99.90499, 20.4487], [99.89692, 20.44789], [99.89301, 20.44311], [99.89168, 20.44548], [99.88451, 20.44596], [99.88211, 20.44488], [99.86383, 20.44371], [99.81096, 20.33687], [99.68255, 20.32077], [99.46008, 20.39673], [99.46077, 20.36198], [99.5569, 20.20676], [99.52943, 20.14811], [99.416, 20.08614], [99.20328, 20.12877], [99.0735, 20.10298], [98.98679, 19.7419], [98.83661, 19.80931], [98.56065, 19.67807], [98.51182, 19.71303], [98.24884, 19.67876], [98.13829, 19.78541], [98.03314, 19.80941], [98.04364, 19.65755], [97.84715, 19.55782], [97.88423, 19.5041], [97.78769, 19.39429], [97.84186, 19.29526], [97.78606, 19.26769], [97.84024, 19.22217], [97.83479, 19.09972], [97.73797, 19.04261], [97.73654, 18.9812], [97.66487, 18.9371], [97.73836, 18.88478], [97.76752, 18.58097], [97.5258, 18.4939], [97.36444, 18.57138], [97.34522, 18.54596], [97.50383, 18.26844], [97.56219, 18.33885], [97.64116, 18.29778], [97.60841, 18.23846], [97.73723, 17.97912], [97.66794, 17.88005], [97.76407, 17.71595], [97.91829, 17.54504], [98.11185, 17.36829], [98.10439, 17.33847], [98.34566, 17.04822], [98.39441, 17.06266], [98.52624, 16.89979], [98.49603, 16.8446], [98.53833, 16.81934], [98.46994, 16.73613], [98.50253, 16.7139], [98.49713, 16.69022], [98.51043, 16.70107], [98.51579, 16.69433], [98.51472, 16.68521], [98.51833, 16.676], [98.51113, 16.64503], [98.5695, 16.62826], [98.57912, 16.55983], [98.63817, 16.47424], [98.68074, 16.27068], [98.84485, 16.42354], [98.92656, 16.36425], [98.8376, 16.11706], [98.69585, 16.13353], [98.57019, 16.04578], [98.59853, 15.87197], [98.541, 15.65406], [98.58598, 15.46821], [98.56027, 15.33471], [98.4866, 15.39154], [98.39351, 15.34177], [98.41906, 15.27103], [98.40522, 15.25268], [98.30446, 15.30667], [98.22, 15.21327], [98.18821, 15.13125], [98.24874, 14.83013], [98.56762, 14.37701], [98.97356, 14.04868], [99.16695, 13.72621], [99.20617, 13.20575], [99.12225, 13.19847], [99.10646, 13.05804], [99.18748, 12.9898], [99.18905, 12.84799], [99.29254, 12.68921], [99.409, 12.60603], [99.47519, 12.1353], [99.56445, 12.14805], [99.53424, 12.02317], [99.64891, 11.82699], [99.64108, 11.78948], [99.5672, 11.62732], [99.47598, 11.62434], [99.39485, 11.3925], [99.31573, 11.32081], [99.32756, 11.28545], [99.06938, 10.94857], [99.02337, 10.97217], [98.99701, 10.92962], [99.0069, 10.85485], [98.86819, 10.78336], [98.78511, 10.68351], [98.77275, 10.62548], [98.81944, 10.52761], [98.7391, 10.31488], [98.55174, 9.92804], [98.52291, 9.92389], [98.47298, 9.95782], [98.33094, 9.91973], [98.12555, 9.44056], [97.63455, 9.60854], [97.19814, 8.18901], [99.31854, 5.99868], [99.50117, 6.44501], [99.91873, 6.50233], [100.0756, 6.4045], [100.12, 6.42105], [100.19511, 6.72559], [100.29651, 6.68439], [100.30828, 6.66462], [100.31618, 6.66781], [100.31884, 6.66423], [100.32671, 6.66526], [100.32607, 6.65933], [100.31929, 6.65413], [100.35413, 6.54932], [100.41152, 6.52299], [100.41791, 6.5189], [100.42351, 6.51762], [100.43027, 6.52389], [100.66986, 6.45086], [100.74361, 6.50811], [100.74822, 6.46231], [100.81045, 6.45086], [100.85884, 6.24929], [101.10313, 6.25617], [101.12618, 6.19431], [101.06165, 6.14161], [101.12388, 6.11411], [101.087, 5.9193], [101.02708, 5.91013], [100.98815, 5.79464], [101.14062, 5.61613], [101.25755, 5.71065], [101.25524, 5.78633], [101.58019, 5.93534], [101.69773, 5.75881], [101.75074, 5.79091], [101.80144, 5.74505], [101.89188, 5.8386], [101.91776, 5.84269], [101.92819, 5.85511], [101.94712, 5.98421], [101.9714, 6.00575], [101.97114, 6.01992], [101.99209, 6.04075], [102.01835, 6.05407], [102.09182, 6.14161], [102.07732, 6.193], [102.08127, 6.22679], [102.09086, 6.23546], [102.46318, 7.22462], [102.47649, 9.66162], [102.52395, 11.25257], [102.91449, 11.65512], [102.90973, 11.75613], [102.83957, 11.8519], [102.78427, 11.98746], [102.77026, 12.06815], [102.70176, 12.1686], [102.73134, 12.37091], [102.78116, 12.40284], [102.7796, 12.43781], [102.57567, 12.65358], [102.51963, 12.66117], [102.4994, 12.71736], [102.53053, 12.77506], [102.49335, 12.92711], [102.48694, 12.97537], [102.52275, 12.99813], [102.46011, 13.08057], [102.43422, 13.09061], [102.36146, 13.26006], [102.36001, 13.31142], [102.34611, 13.35618], [102.35692, 13.38274], [102.35563, 13.47307], [102.361, 13.50551], [102.33828, 13.55613], [102.36859, 13.57488], [102.44601, 13.5637], [102.5358, 13.56933], [102.57573, 13.60461], [102.62483, 13.60883], [102.58635, 13.6286], [102.5481, 13.6589], [102.56848, 13.69366], [102.72727, 13.77806], [102.77864, 13.93374], [102.91251, 14.01531], [102.93275, 14.19044], [103.16469, 14.33075], [103.39353, 14.35639], [103.53518, 14.42575], [103.71109, 14.4348], [103.70175, 14.38052], [103.93836, 14.3398], [104.27616, 14.39861], [104.55014, 14.36091], [104.69335, 14.42726], [104.97667, 14.38806], [105.02804, 14.23722], [105.08408, 14.20402], [105.14012, 14.23873], [105.17748, 14.34432], [105.20894, 14.34967], [105.43783, 14.43865], [105.53864, 14.55731], [105.5121, 14.80802], [105.61162, 15.00037], [105.46661, 15.13132], [105.58043, 15.32724], [105.50662, 15.32054], [105.4692, 15.33709], [105.47635, 15.3796], [105.58191, 15.41031], [105.60446, 15.53301], [105.61756, 15.68792], [105.46573, 15.74742], [105.42285, 15.76971], [105.37959, 15.84074], [105.34115, 15.92737], [105.38508, 15.987], [105.42001, 16.00657], [105.06204, 16.09792], [105.00262, 16.25627], [104.88057, 16.37311], [104.73349, 16.565], [104.76099, 16.69302], [104.7397, 16.81005], [104.76442, 16.84752], [104.7373, 16.91125], [104.73712, 17.01404], [104.80716, 17.19025], [104.80061, 17.39367], [104.69867, 17.53038], [104.45404, 17.66788], [104.35432, 17.82871], [104.2757, 17.86139], [104.21776, 17.99335], [104.10927, 18.10826], [104.06533, 18.21656], [103.97725, 18.33631], [103.93916, 18.33914], [103.85642, 18.28666], [103.82449, 18.33979], [103.699, 18.34125], [103.60957, 18.40528], [103.47773, 18.42841], [103.41044, 18.4486], [103.30977, 18.4341], [103.24779, 18.37807], [103.23818, 18.34875], [103.29757, 18.30475], [103.17093, 18.2618], [103.14994, 18.23172], [103.1493, 18.17799], [103.07343, 18.12351], [103.07823, 18.03833], [103.0566, 18.00144], [103.01998, 17.97095], [102.9912, 17.9949], [102.95812, 18.0054], [102.86323, 17.97531], [102.81988, 17.94233], [102.79044, 17.93612], [102.75954, 17.89561], [102.68538, 17.86653], [102.67543, 17.84529], [102.69946, 17.81686], [102.68194, 17.80151], [102.59485, 17.83537], [102.5896, 17.84889], [102.61432, 17.92273], [102.60971, 17.95411], [102.59234, 17.96127], [102.45523, 17.97106], [102.11359, 18.21532], [101.88485, 18.02474], [101.78087, 18.07559], [101.72294, 17.92867], [101.44667, 17.7392], [101.15108, 17.47586], [100.96541, 17.57926], [101.02185, 17.87637], [101.1793, 18.0544], [101.19118, 18.2125], [101.15108, 18.25624], [101.18227, 18.34367], [101.06047, 18.43247], [101.27585, 18.68875], [101.22832, 18.73377], [101.25803, 18.89545], [101.35606, 19.04716], [101.261, 19.12717], [101.24911, 19.33334], [101.20604, 19.35296], [101.21347, 19.46223], [101.26991, 19.48324], [101.26545, 19.59242], [101.08928, 19.59748], [100.90302, 19.61901], [100.77231, 19.48324], [100.64606, 19.55884], [100.58219, 19.49164], [100.49604, 19.53504], [100.398, 19.75047], [100.5094, 19.87904], [100.58808, 20.15791], [100.55218, 20.17741], [100.51052, 20.14928], [100.47567, 20.19133], [100.4537, 20.19971], [100.44992, 20.23644], [100.41473, 20.25625], [100.37439, 20.35156], [100.33383, 20.4028], [100.25769, 20.3992], [100.22076, 20.31598], [100.16668, 20.2986], [100.1712, 20.24324], [100.11785, 20.24787], [100.09337, 20.26293], [100.09999, 20.31614], [100.08404, 20.36626]]]]
27257 nameEn: "Tajikistan",
27258 groups: ["143", "142", "UN"],
27259 callingCodes: ["992"]
27262 type: "MultiPolygon",
27263 coordinates: [[[[70.45251, 41.04438], [70.38028, 41.02014], [70.36655, 40.90296], [69.69434, 40.62615], [69.59441, 40.70181], [69.53021, 40.77621], [69.38327, 40.7918], [69.32834, 40.70233], [69.3455, 40.57988], [69.2643, 40.57506], [69.21063, 40.54469], [69.27066, 40.49274], [69.28525, 40.41894], [69.30774, 40.36102], [69.33794, 40.34819], [69.32833, 40.29794], [69.30808, 40.2821], [69.24817, 40.30357], [69.25229, 40.26362], [69.30104, 40.24502], [69.30448, 40.18774], [69.2074, 40.21488], [69.15659, 40.2162], [69.04544, 40.22904], [68.85832, 40.20885], [68.84357, 40.18604], [68.79276, 40.17555], [68.77902, 40.20492], [68.5332, 40.14826], [68.52771, 40.11676], [68.62796, 40.07789], [69.01523, 40.15771], [69.01935, 40.11466], [68.96579, 40.06949], [68.84906, 40.04952], [68.93695, 39.91167], [68.88889, 39.87163], [68.63071, 39.85265], [68.61972, 39.68905], [68.54166, 39.53929], [68.12053, 39.56317], [67.70992, 39.66156], [67.62889, 39.60234], [67.44899, 39.57799], [67.46547, 39.53564], [67.39681, 39.52505], [67.46822, 39.46146], [67.45998, 39.315], [67.36522, 39.31287], [67.33226, 39.23739], [67.67833, 39.14479], [67.68915, 39.00775], [68.09704, 39.02589], [68.19743, 38.85985], [68.06948, 38.82115], [68.12877, 38.73677], [68.05598, 38.71641], [68.0807, 38.64136], [68.05873, 38.56087], [68.11366, 38.47169], [68.06274, 38.39435], [68.13289, 38.40822], [68.40343, 38.19484], [68.27159, 37.91477], [68.12635, 37.93], [67.81566, 37.43107], [67.8474, 37.31594], [67.78329, 37.1834], [67.7803, 37.08978], [67.87917, 37.0591], [68.02194, 36.91923], [68.18542, 37.02074], [68.27605, 37.00977], [68.29253, 37.10621], [68.41201, 37.10402], [68.41888, 37.13906], [68.61851, 37.19815], [68.6798, 37.27906], [68.81438, 37.23862], [68.80889, 37.32494], [68.91189, 37.26704], [68.88168, 37.33368], [68.96407, 37.32603], [69.03274, 37.25174], [69.25152, 37.09426], [69.39529, 37.16752], [69.45022, 37.23315], [69.36645, 37.40462], [69.44954, 37.4869], [69.51888, 37.5844], [69.80041, 37.5746], [69.84435, 37.60616], [69.93362, 37.61378], [69.95971, 37.5659], [70.15015, 37.52519], [70.28243, 37.66706], [70.27694, 37.81258], [70.1863, 37.84296], [70.17206, 37.93276], [70.4898, 38.12546], [70.54673, 38.24541], [70.60407, 38.28046], [70.61526, 38.34774], [70.64966, 38.34999], [70.69189, 38.37031], [70.6761, 38.39144], [70.67438, 38.40597], [70.69807, 38.41861], [70.72485, 38.4131], [70.75455, 38.4252], [70.77132, 38.45548], [70.78581, 38.45502], [70.78702, 38.45031], [70.79766, 38.44944], [70.80521, 38.44447], [70.81697, 38.44507], [70.82538, 38.45394], [70.84376, 38.44688], [70.88719, 38.46826], [70.92728, 38.43021], [70.98693, 38.48862], [71.03545, 38.44779], [71.0556, 38.40176], [71.09542, 38.42517], [71.10592, 38.42077], [71.10957, 38.40671], [71.1451, 38.40106], [71.21291, 38.32797], [71.33114, 38.30339], [71.33869, 38.27335], [71.37803, 38.25641], [71.36444, 38.15358], [71.29878, 38.04429], [71.28922, 38.01272], [71.27622, 37.99946], [71.27278, 37.96496], [71.24969, 37.93031], [71.2809, 37.91995], [71.296, 37.93403], [71.32871, 37.88564], [71.51565, 37.95349], [71.58843, 37.92425], [71.59255, 37.79956], [71.55752, 37.78677], [71.54324, 37.77104], [71.53053, 37.76534], [71.55234, 37.73209], [71.54186, 37.69691], [71.51972, 37.61945], [71.5065, 37.60912], [71.49693, 37.53527], [71.50616, 37.50733], [71.5256, 37.47971], [71.49612, 37.4279], [71.47685, 37.40281], [71.4862, 37.33405], [71.49821, 37.31975], [71.50674, 37.31502], [71.48536, 37.26017], [71.4824, 37.24921], [71.48339, 37.23937], [71.47386, 37.2269], [71.4555, 37.21418], [71.4494, 37.18137], [71.44127, 37.11856], [71.43097, 37.05855], [71.45578, 37.03094], [71.46923, 36.99925], [71.48481, 36.93218], [71.51502, 36.89128], [71.57195, 36.74943], [71.67083, 36.67346], [71.83229, 36.68084], [72.31676, 36.98115], [72.54095, 37.00007], [72.66381, 37.02014], [72.79693, 37.22222], [73.06884, 37.31729], [73.29633, 37.46495], [73.77197, 37.4417], [73.76647, 37.33913], [73.61129, 37.27469], [73.64974, 37.23643], [73.82552, 37.22659], [73.8564, 37.26158], [74.20308, 37.34208], [74.23339, 37.41116], [74.41055, 37.3948], [74.56161, 37.37734], [74.68383, 37.3948], [74.8294, 37.3435], [74.88887, 37.23275], [75.12328, 37.31839], [75.09719, 37.37297], [75.15899, 37.41443], [75.06011, 37.52779], [74.94338, 37.55501], [74.8912, 37.67576], [75.00935, 37.77486], [74.92416, 37.83428], [74.9063, 38.03033], [74.82665, 38.07359], [74.80331, 38.19889], [74.69894, 38.22155], [74.69619, 38.42947], [74.51217, 38.47034], [74.17022, 38.65504], [73.97933, 38.52945], [73.79806, 38.61106], [73.80656, 38.66449], [73.7033, 38.84782], [73.7445, 38.93867], [73.82964, 38.91517], [73.81728, 39.04007], [73.75823, 39.023], [73.60638, 39.24534], [73.54572, 39.27567], [73.55396, 39.3543], [73.5004, 39.38402], [73.59241, 39.40843], [73.59831, 39.46425], [73.45096, 39.46677], [73.31912, 39.38615], [73.18454, 39.35536], [72.85934, 39.35116], [72.62027, 39.39696], [72.33173, 39.33093], [72.23834, 39.17248], [72.17242, 39.2661], [72.09689, 39.26823], [72.04059, 39.36704], [71.90601, 39.27674], [71.79202, 39.27355], [71.7522, 39.32031], [71.80164, 39.40631], [71.76816, 39.45456], [71.62688, 39.44056], [71.5517, 39.45722], [71.55856, 39.57588], [71.49814, 39.61397], [71.08752, 39.50704], [71.06418, 39.41586], [70.7854, 39.38933], [70.64087, 39.58792], [70.44757, 39.60128], [70.2869, 39.53141], [70.11111, 39.58223], [69.87491, 39.53882], [69.68677, 39.59281], [69.3594, 39.52516], [69.26938, 39.8127], [69.35649, 40.01994], [69.43134, 39.98431], [69.43557, 39.92877], [69.53615, 39.93991], [69.5057, 40.03277], [69.53855, 40.0887], [69.53794, 40.11833], [69.55555, 40.12296], [69.57615, 40.10524], [69.64704, 40.12165], [69.67001, 40.10639], [70.01283, 40.23288], [70.58297, 40.00891], [70.57384, 39.99394], [70.47557, 39.93216], [70.55033, 39.96619], [70.58912, 39.95211], [70.65946, 39.9878], [70.65827, 40.0981], [70.7928, 40.12797], [70.80495, 40.16813], [70.9818, 40.22392], [70.8607, 40.217], [70.62342, 40.17396], [70.56394, 40.26421], [70.57149, 40.3442], [70.37511, 40.38605], [70.32626, 40.45174], [70.49871, 40.52503], [70.80009, 40.72825], [70.45251, 41.04438]]], [[[70.68112, 40.90612], [70.6158, 40.97661], [70.56077, 41.00642], [70.54223, 40.98787], [70.57501, 40.98941], [70.6721, 40.90555], [70.68112, 40.90612]]], [[[70.74189, 39.86319], [70.53651, 39.89155], [70.52631, 39.86989], [70.54998, 39.85137], [70.59667, 39.83542], [70.63105, 39.77923], [70.74189, 39.86319]]]]
27271 wikidata: "Q36823",
27274 groups: ["061", "009", "UN"],
27276 callingCodes: ["690"]
27279 type: "MultiPolygon",
27280 coordinates: [[[[-168.251, -9.44289], [-174.18635, -7.80441], [-174.17993, -10.13616], [-168.251, -9.44289]]]]
27289 nameEn: "East Timor",
27290 aliases: ["Timor-Leste", "TP"],
27291 groups: ["035", "142", "UN"],
27293 callingCodes: ["670"]
27296 type: "MultiPolygon",
27297 coordinates: [[[[124.46701, -9.13002], [124.94011, -8.85617], [124.97742, -9.08128], [125.11764, -8.96359], [125.18632, -9.03142], [125.18907, -9.16434], [125.09434, -9.19669], [125.04044, -9.17093], [124.97892, -9.19281], [125.09025, -9.46406], [125.68138, -9.85176], [127.55165, -9.05052], [127.42116, -8.22471], [125.87691, -8.31789], [125.58506, -7.95311], [124.92337, -8.75859], [124.33472, -9.11416], [124.04628, -9.22671], [124.04286, -9.34243], [124.10539, -9.41206], [124.14517, -9.42324], [124.21247, -9.36904], [124.28115, -9.42189], [124.28115, -9.50453], [124.3535, -9.48493], [124.35258, -9.43002], [124.38554, -9.3582], [124.45971, -9.30263], [124.46701, -9.13002]]]]
27306 nameEn: "Turkmenistan",
27307 groups: ["143", "142", "UN"],
27308 callingCodes: ["993"]
27311 type: "MultiPolygon",
27312 coordinates: [[[[60.5078, 41.21694], [60.06581, 41.4363], [60.18117, 41.60082], [60.06032, 41.76287], [60.08504, 41.80997], [60.33223, 41.75058], [59.95046, 41.97966], [60.0356, 42.01028], [60.04659, 42.08982], [59.96419, 42.1428], [60.00539, 42.212], [59.94633, 42.27655], [59.4341, 42.29738], [59.2955, 42.37064], [59.17317, 42.52248], [58.93422, 42.5407], [58.6266, 42.79314], [58.57991, 42.64988], [58.27504, 42.69632], [58.14321, 42.62159], [58.29427, 42.56497], [58.51674, 42.30348], [58.40688, 42.29535], [58.3492, 42.43335], [57.99214, 42.50021], [57.90975, 42.4374], [57.92897, 42.24047], [57.84932, 42.18555], [57.6296, 42.16519], [57.30275, 42.14076], [57.03633, 41.92043], [56.96218, 41.80383], [57.03359, 41.41777], [57.13796, 41.36625], [57.03423, 41.25435], [56.00314, 41.32584], [55.45471, 41.25609], [54.95182, 41.92424], [54.20635, 42.38477], [52.97575, 42.1308], [52.47884, 41.78034], [52.26048, 41.69249], [51.7708, 40.29239], [53.89734, 37.3464], [54.24565, 37.32047], [54.36211, 37.34912], [54.58664, 37.45809], [54.67247, 37.43532], [54.77822, 37.51597], [54.81804, 37.61285], [54.77684, 37.62264], [54.851, 37.75739], [55.13412, 37.94705], [55.44152, 38.08564], [55.76561, 38.12238], [55.97847, 38.08024], [56.33278, 38.08132], [56.32454, 38.18502], [56.43303, 38.26054], [56.62255, 38.24005], [56.73928, 38.27887], [57.03453, 38.18717], [57.21169, 38.28965], [57.37236, 38.09321], [57.35042, 37.98546], [57.79534, 37.89299], [58.21399, 37.77281], [58.22999, 37.6856], [58.39959, 37.63134], [58.47786, 37.6433], [58.5479, 37.70526], [58.6921, 37.64548], [58.9338, 37.67374], [59.22905, 37.51161], [59.33507, 37.53146], [59.39797, 37.47892], [59.39385, 37.34257], [59.55178, 37.13594], [59.74678, 37.12499], [60.00768, 37.04102], [60.34767, 36.63214], [61.14516, 36.64644], [61.18187, 36.55348], [61.1393, 36.38782], [61.22719, 36.12759], [61.12007, 35.95992], [61.22444, 35.92879], [61.26152, 35.80749], [61.22719, 35.67038], [61.27371, 35.61482], [61.58742, 35.43803], [61.77693, 35.41341], [61.97743, 35.4604], [62.05709, 35.43803], [62.15871, 35.33278], [62.29191, 35.25964], [62.29878, 35.13312], [62.48006, 35.28796], [62.62288, 35.22067], [62.74098, 35.25432], [62.90853, 35.37086], [63.0898, 35.43131], [63.12276, 35.53196], [63.10079, 35.63024], [63.23262, 35.67487], [63.10318, 35.81782], [63.12276, 35.86208], [63.29579, 35.85985], [63.53475, 35.90881], [63.56496, 35.95106], [63.98519, 36.03773], [64.05385, 36.10433], [64.43288, 36.24401], [64.57295, 36.34362], [64.62514, 36.44311], [64.61141, 36.6351], [64.97945, 37.21913], [65.51778, 37.23881], [65.64263, 37.34388], [65.64137, 37.45061], [65.72274, 37.55438], [66.30993, 37.32409], [66.55743, 37.35409], [66.52303, 37.39827], [66.65761, 37.45497], [66.52852, 37.58568], [66.53676, 37.80084], [66.67684, 37.96776], [66.56697, 38.0435], [66.41042, 38.02403], [66.24013, 38.16238], [65.83913, 38.25733], [65.55873, 38.29052], [64.32576, 38.98691], [64.19086, 38.95561], [63.70778, 39.22349], [63.6913, 39.27666], [62.43337, 39.98528], [62.34273, 40.43206], [62.11751, 40.58242], [61.87856, 41.12257], [61.4446, 41.29407], [61.39732, 41.19873], [61.33199, 41.14946], [61.22212, 41.14946], [61.03261, 41.25691], [60.5078, 41.21694]]]]
27322 groups: ["015", "002", "UN"],
27323 callingCodes: ["216"]
27326 type: "MultiPolygon",
27327 coordinates: [[[[11.2718, 37.6713], [7.89009, 38.19924], [8.59123, 37.14286], [8.64044, 36.9401], [8.62972, 36.86499], [8.67706, 36.8364], [8.57613, 36.78062], [8.46537, 36.7706], [8.47609, 36.66607], [8.16167, 36.48817], [8.18936, 36.44939], [8.40731, 36.42208], [8.2626, 35.91733], [8.26472, 35.73669], [8.35371, 35.66373], [8.36086, 35.47774], [8.30329, 35.29884], [8.47318, 35.23376], [8.3555, 35.10007], [8.30727, 34.95378], [8.25189, 34.92009], [8.29655, 34.72798], [8.20482, 34.57575], [7.86264, 34.3987], [7.81242, 34.21841], [7.74207, 34.16492], [7.66174, 34.20167], [7.52851, 34.06493], [7.54088, 33.7726], [7.73687, 33.42114], [7.83028, 33.18851], [8.11433, 33.10175], [8.1179, 33.05086], [8.31895, 32.83483], [8.35999, 32.50101], [9.07483, 32.07865], [9.55544, 30.23971], [9.76848, 30.34366], [9.88152, 30.34074], [10.29516, 30.90337], [10.12239, 31.42098], [10.31364, 31.72648], [10.48497, 31.72956], [10.62788, 31.96629], [10.7315, 31.97235], [11.04234, 32.2145], [11.53898, 32.4138], [11.57828, 32.48013], [11.46037, 32.6307], [11.51549, 33.09826], [11.55852, 33.1409], [11.58941, 33.36891], [11.2718, 37.6713]]]]
27337 groups: ["061", "009", "UN"],
27339 callingCodes: ["676"]
27342 type: "MultiPolygon",
27343 coordinates: [[[[-176.74538, -22.89767], [-180, -22.90585], [-180, -24.21376], [-173.10761, -24.19665], [-173.13438, -14.94228], [-176.76826, -14.95183], [-176.74538, -22.89767]]]]
27353 groups: ["145", "142", "UN"],
27354 callingCodes: ["90"]
27357 type: "MultiPolygon",
27358 coordinates: [[[[41.54366, 41.52185], [40.89217, 41.72528], [34.8305, 42.4581], [28.32297, 41.98371], [28.02971, 41.98066], [27.91479, 41.97902], [27.83492, 41.99709], [27.81235, 41.94803], [27.69949, 41.97515], [27.55191, 41.90928], [27.52379, 41.93756], [27.45478, 41.96591], [27.27411, 42.10409], [27.22376, 42.10152], [27.19251, 42.06028], [27.08486, 42.08735], [27.03277, 42.0809], [26.95638, 42.00741], [26.79143, 41.97386], [26.62996, 41.97644], [26.56051, 41.92995], [26.57961, 41.90024], [26.53968, 41.82653], [26.36952, 41.82265], [26.33589, 41.76802], [26.32952, 41.73637], [26.35957, 41.71149], [26.47958, 41.67037], [26.5209, 41.62592], [26.59196, 41.60491], [26.59742, 41.48058], [26.61767, 41.42281], [26.62997, 41.34613], [26.5837, 41.32131], [26.5209, 41.33993], [26.39861, 41.25053], [26.32259, 41.24929], [26.31928, 41.07386], [26.3606, 41.02027], [26.33297, 40.98388], [26.35894, 40.94292], [26.32259, 40.94042], [26.28623, 40.93005], [26.29441, 40.89119], [26.26169, 40.9168], [26.20856, 40.86048], [26.21351, 40.83298], [26.15685, 40.80709], [26.12854, 40.77339], [26.12495, 40.74283], [26.08638, 40.73214], [26.0754, 40.72772], [26.03489, 40.73051], [25.94795, 40.72797], [26.04292, 40.3958], [25.61285, 40.17161], [25.94257, 39.39358], [26.43357, 39.43096], [26.70773, 39.0312], [26.61814, 38.81372], [26.21136, 38.65436], [26.32173, 38.48731], [26.24183, 38.44695], [26.21136, 38.17558], [27.05537, 37.9131], [27.16428, 37.72343], [26.99377, 37.69034], [26.95583, 37.64989], [27.14757, 37.32], [27.20312, 36.94571], [27.45627, 36.9008], [27.24613, 36.71622], [27.46117, 36.53789], [27.89482, 36.69898], [27.95037, 36.46155], [28.23708, 36.56812], [29.30783, 36.01033], [29.48192, 36.18377], [29.61002, 36.1731], [29.61805, 36.14179], [29.69611, 36.10365], [29.73302, 35.92555], [32.82353, 35.70297], [35.51152, 36.10954], [35.931, 35.92109], [35.98499, 35.94107], [36.00514, 35.94113], [36.01844, 35.92403], [35.99829, 35.88242], [36.11827, 35.85923], [36.13919, 35.83692], [36.14029, 35.81015], [36.1623, 35.80925], [36.17441, 35.92076], [36.19973, 35.95195], [36.25366, 35.96264], [36.27678, 35.94839], [36.29769, 35.96086], [36.28338, 36.00273], [36.30099, 36.00985], [36.33956, 35.98687], [36.37474, 36.01163], [36.39206, 36.22088], [36.4617, 36.20461], [36.50463, 36.2419], [36.6125, 36.22592], [36.68672, 36.23677], [36.65653, 36.33861], [36.6081, 36.33772], [36.54206, 36.49539], [36.58829, 36.58295], [36.57398, 36.65186], [36.62681, 36.71189], [36.61581, 36.74629], [36.66727, 36.82901], [36.99557, 36.75997], [36.99886, 36.74012], [37.04399, 36.73483], [37.04619, 36.71101], [37.01647, 36.69512], [37.02088, 36.66422], [37.08279, 36.63495], [37.10894, 36.6704], [37.16177, 36.66069], [37.21988, 36.6736], [37.47253, 36.63243], [37.49103, 36.66904], [37.68048, 36.75065], [37.81974, 36.76055], [38.21064, 36.91842], [38.38859, 36.90064], [38.55908, 36.84429], [38.74042, 36.70629], [39.03217, 36.70911], [39.21538, 36.66834], [39.81589, 36.75538], [40.69136, 37.0996], [40.90856, 37.13147], [41.21937, 37.07665], [41.515, 37.08084], [42.00894, 37.17209], [42.18225, 37.28569], [42.19301, 37.31323], [42.2112, 37.32491], [42.22257, 37.31395], [42.22381, 37.30238], [42.20454, 37.28715], [42.21548, 37.28026], [42.23683, 37.2863], [42.26039, 37.27017], [42.2824, 37.2798], [42.34735, 37.22548], [42.32313, 37.17814], [42.35724, 37.10998], [42.56725, 37.14878], [42.78887, 37.38615], [42.93705, 37.32015], [43.11403, 37.37436], [43.30083, 37.30629], [43.33508, 37.33105], [43.50787, 37.24436], [43.56702, 37.25675], [43.63085, 37.21957], [43.7009, 37.23692], [43.8052, 37.22825], [43.82699, 37.19477], [43.84878, 37.22205], [43.90949, 37.22453], [44.02002, 37.33229], [44.13521, 37.32486], [44.2613, 37.25055], [44.27998, 37.16501], [44.22239, 37.15756], [44.18503, 37.09551], [44.25975, 36.98119], [44.30645, 36.97373], [44.35937, 37.02843], [44.35315, 37.04955], [44.38117, 37.05825], [44.42631, 37.05825], [44.63179, 37.19229], [44.76698, 37.16162], [44.78319, 37.1431], [44.7868, 37.16644], [44.75986, 37.21549], [44.81021, 37.2915], [44.58449, 37.45018], [44.61401, 37.60165], [44.56887, 37.6429], [44.62096, 37.71985], [44.55498, 37.783], [44.45948, 37.77065], [44.3883, 37.85433], [44.22509, 37.88859], [44.42476, 38.25763], [44.50115, 38.33939], [44.44386, 38.38295], [44.38309, 38.36117], [44.3119, 38.37887], [44.3207, 38.49799], [44.32058, 38.62752], [44.28065, 38.6465], [44.26155, 38.71427], [44.30322, 38.81581], [44.18863, 38.93881], [44.20946, 39.13975], [44.1043, 39.19842], [44.03667, 39.39223], [44.22452, 39.4169], [44.29818, 39.378], [44.37921, 39.4131], [44.42832, 39.4131], [44.41849, 39.56659], [44.48111, 39.61579], [44.47298, 39.68788], [44.6137, 39.78393], [44.65422, 39.72163], [44.71806, 39.71124], [44.81043, 39.62677], [44.80977, 39.65768], [44.75779, 39.7148], [44.61845, 39.8281], [44.46635, 39.97733], [44.26973, 40.04866], [44.1778, 40.02845], [44.1057, 40.03555], [43.92307, 40.01787], [43.65688, 40.11199], [43.65221, 40.14889], [43.71136, 40.16673], [43.59928, 40.34019], [43.60862, 40.43267], [43.54791, 40.47413], [43.63664, 40.54159], [43.7425, 40.66805], [43.74872, 40.7365], [43.67712, 40.84846], [43.67712, 40.93084], [43.58683, 40.98961], [43.47319, 41.02251], [43.44984, 41.0988], [43.4717, 41.12611], [43.44973, 41.17666], [43.36118, 41.2028], [43.23096, 41.17536], [43.1945, 41.25242], [43.13373, 41.25503], [43.21707, 41.30331], [43.02956, 41.37891], [42.8785, 41.50516], [42.84899, 41.47265], [42.78995, 41.50126], [42.84471, 41.58912], [42.72794, 41.59714], [42.59202, 41.58183], [42.51772, 41.43606], [42.26387, 41.49346], [41.95134, 41.52466], [41.81939, 41.43621], [41.7124, 41.47417], [41.7148, 41.4932], [41.54366, 41.52185]]]]
27367 nameEn: "Trinidad and Tobago",
27368 groups: ["029", "003", "419", "019", "UN"],
27370 callingCodes: ["1 868"]
27373 type: "MultiPolygon",
27374 coordinates: [[[[-61.62505, 11.18974], [-62.08693, 10.04435], [-60.89962, 9.81445], [-60.07172, 11.77667], [-61.62505, 11.18974]]]]
27384 groups: ["061", "009", "UN"],
27386 callingCodes: ["688"]
27389 type: "MultiPolygon",
27390 coordinates: [[[[174, -5], [174, -11.5], [179.99999, -11.5], [179.99999, -5], [174, -5]]]]
27401 groups: ["030", "142"],
27402 callingCodes: ["886"]
27405 type: "MultiPolygon",
27406 coordinates: [[[[121.8109, 21.77688], [122.26612, 25.98197], [120.49232, 25.22863], [118.56434, 24.49266], [118.42453, 24.54644], [118.35291, 24.51645], [118.28244, 24.51231], [118.11703, 24.39734], [120.69238, 21.52331], [121.8109, 21.77688]]]]
27415 nameEn: "Tanzania",
27416 groups: ["014", "202", "002", "UN"],
27418 callingCodes: ["255"]
27421 type: "MultiPolygon",
27422 coordinates: [[[[30.80408, -0.99911], [30.76635, -0.9852], [30.70631, -1.01175], [30.64166, -1.06601], [30.47194, -1.0555], [30.45116, -1.10641], [30.50889, -1.16412], [30.57123, -1.33264], [30.71974, -1.43244], [30.84079, -1.64652], [30.80802, -1.91477], [30.89303, -2.08223], [30.83915, -2.35795], [30.54501, -2.41404], [30.41789, -2.66266], [30.52747, -2.65841], [30.40662, -2.86151], [30.4987, -2.9573], [30.57926, -2.89791], [30.6675, -2.98987], [30.83823, -2.97837], [30.84165, -3.25152], [30.45915, -3.56532], [30.22042, -4.01738], [30.03323, -4.26631], [29.88172, -4.35743], [29.82885, -4.36153], [29.77289, -4.41733], [29.75109, -4.45836], [29.63827, -4.44681], [29.43673, -4.44845], [29.52552, -6.2731], [30.2567, -7.14121], [30.79243, -8.27382], [31.00796, -8.58615], [31.37533, -8.60769], [31.57147, -8.70619], [31.57147, -8.81388], [31.71158, -8.91386], [31.81587, -8.88618], [31.94663, -8.93846], [31.94196, -9.02303], [31.98866, -9.07069], [32.08206, -9.04609], [32.16146, -9.05993], [32.25486, -9.13371], [32.43543, -9.11988], [32.49147, -9.14754], [32.53661, -9.24281], [32.75611, -9.28583], [32.76233, -9.31963], [32.95389, -9.40138], [32.99397, -9.36712], [33.14925, -9.49322], [33.31581, -9.48554], [33.48052, -9.62442], [33.76677, -9.58516], [33.93298, -9.71647], [33.9638, -9.62206], [33.95829, -9.54066], [34.03865, -9.49398], [34.54499, -10.0678], [34.51911, -10.12279], [34.57581, -10.56271], [34.65946, -10.6828], [34.67047, -10.93796], [34.61161, -11.01611], [34.63305, -11.11731], [34.79375, -11.32245], [34.91153, -11.39799], [34.96296, -11.57354], [35.63599, -11.55927], [35.82767, -11.41081], [36.19094, -11.57593], [36.19094, -11.70008], [36.62068, -11.72884], [36.80309, -11.56836], [37.3936, -11.68949], [37.76614, -11.53352], [37.8388, -11.3123], [37.93618, -11.26228], [38.21598, -11.27289], [38.47258, -11.4199], [38.88996, -11.16978], [39.24395, -11.17433], [39.58249, -10.96043], [40.00295, -10.80255], [40.44265, -10.4618], [40.74206, -10.25691], [40.14328, -4.64201], [39.62121, -4.68136], [39.44306, -4.93877], [39.21631, -4.67835], [37.81321, -3.69179], [37.75036, -3.54243], [37.63099, -3.50723], [37.5903, -3.42735], [37.71745, -3.304], [37.67199, -3.06222], [34.0824, -1.02264], [34.03084, -1.05101], [34.02286, -1.00779], [33.93107, -0.99298], [30.80408, -0.99911]]]]
27432 groups: ["151", "150", "UN"],
27433 callingCodes: ["380"]
27436 type: "MultiPolygon",
27437 coordinates: [[[[33.57318, 46.10317], [33.61467, 46.13561], [33.63854, 46.14147], [33.61517, 46.22615], [33.646, 46.23028], [33.74047, 46.18555], [33.79715, 46.20482], [33.85234, 46.19863], [33.91549, 46.15938], [34.05272, 46.10838], [34.07311, 46.11769], [34.12929, 46.10494], [34.181, 46.06804], [34.25111, 46.0532], [34.33912, 46.06114], [34.41221, 46.00245], [34.44155, 45.95995], [34.48729, 45.94267], [34.52011, 45.95097], [34.55889, 45.99347], [34.60861, 45.99347], [34.66679, 45.97136], [34.75479, 45.90705], [34.80153, 45.90047], [34.79905, 45.81009], [34.96015, 45.75634], [35.23066, 45.79231], [37.62608, 46.82615], [38.12112, 46.86078], [38.3384, 46.98085], [38.22955, 47.12069], [38.23049, 47.2324], [38.32112, 47.2585], [38.33074, 47.30508], [38.22225, 47.30788], [38.28954, 47.39255], [38.28679, 47.53552], [38.35062, 47.61631], [38.76379, 47.69346], [38.79628, 47.81109], [38.87979, 47.87719], [39.73935, 47.82876], [39.82213, 47.96396], [39.77544, 48.04206], [39.88256, 48.04482], [39.83724, 48.06501], [39.94847, 48.22811], [40.00752, 48.22445], [39.99241, 48.31768], [39.97325, 48.31399], [39.9693, 48.29904], [39.95248, 48.29972], [39.91465, 48.26743], [39.90041, 48.3049], [39.84273, 48.30947], [39.84136, 48.33321], [39.94847, 48.35055], [39.88794, 48.44226], [39.86196, 48.46633], [39.84548, 48.57821], [39.79764, 48.58668], [39.67226, 48.59368], [39.71765, 48.68673], [39.73104, 48.7325], [39.79466, 48.83739], [39.97182, 48.79398], [40.08168, 48.87443], [40.03636, 48.91957], [39.98967, 48.86901], [39.78368, 48.91596], [39.74874, 48.98675], [39.72649, 48.9754], [39.71353, 48.98959], [39.6683, 48.99454], [39.6836, 49.05121], [39.93437, 49.05709], [40.01988, 49.1761], [40.22176, 49.25683], [40.18331, 49.34996], [40.14912, 49.37681], [40.1141, 49.38798], [40.03087, 49.45452], [40.03636, 49.52321], [40.16683, 49.56865], [40.13249, 49.61672], [39.84548, 49.56064], [39.65047, 49.61761], [39.59142, 49.73758], [39.44496, 49.76067], [39.27968, 49.75976], [39.1808, 49.88911], [38.9391, 49.79524], [38.90477, 49.86787], [38.73311, 49.90238], [38.68677, 50.00904], [38.65688, 49.97176], [38.35408, 50.00664], [38.32524, 50.08866], [38.18517, 50.08161], [38.21675, 49.98104], [38.02999, 49.90592], [38.02999, 49.94482], [37.90776, 50.04194], [37.79515, 50.08425], [37.75807, 50.07896], [37.61113, 50.21976], [37.62879, 50.24481], [37.62486, 50.29966], [37.47243, 50.36277], [37.48204, 50.46079], [37.08468, 50.34935], [36.91762, 50.34963], [36.69377, 50.26982], [36.64571, 50.218], [36.56655, 50.2413], [36.58371, 50.28563], [36.47817, 50.31457], [36.30101, 50.29088], [36.20763, 50.3943], [36.06893, 50.45205], [35.8926, 50.43829], [35.80388, 50.41356], [35.73659, 50.35489], [35.61711, 50.35707], [35.58003, 50.45117], [35.47463, 50.49247], [35.39464, 50.64751], [35.48116, 50.66405], [35.47704, 50.77274], [35.41367, 50.80227], [35.39307, 50.92145], [35.32598, 50.94524], [35.40837, 51.04119], [35.31774, 51.08434], [35.20375, 51.04723], [35.12685, 51.16191], [35.14058, 51.23162], [34.97304, 51.2342], [34.82472, 51.17483], [34.6874, 51.18], [34.6613, 51.25053], [34.38802, 51.2746], [34.31661, 51.23936], [34.23009, 51.26429], [34.33446, 51.363], [34.22048, 51.4187], [34.30562, 51.5205], [34.17599, 51.63253], [34.07765, 51.67065], [34.42922, 51.72852], [34.41136, 51.82793], [34.09413, 52.00835], [34.11199, 52.14087], [34.05239, 52.20132], [33.78789, 52.37204], [33.55718, 52.30324], [33.48027, 52.31499], [33.51323, 52.35779], [33.18913, 52.3754], [32.89937, 52.2461], [32.85405, 52.27888], [32.69475, 52.25535], [32.54781, 52.32423], [32.3528, 52.32842], [32.38988, 52.24946], [32.33083, 52.23685], [32.34044, 52.1434], [32.2777, 52.10266], [32.23331, 52.08085], [32.08813, 52.03319], [31.92159, 52.05144], [31.96141, 52.08015], [31.85018, 52.11305], [31.81722, 52.09955], [31.7822, 52.11406], [31.38326, 52.12991], [31.25142, 52.04131], [31.13332, 52.1004], [30.95589, 52.07775], [30.90897, 52.00699], [30.76443, 51.89739], [30.68804, 51.82806], [30.51946, 51.59649], [30.64992, 51.35014], [30.56203, 51.25655], [30.36153, 51.33984], [30.34642, 51.42555], [30.17888, 51.51025], [29.77376, 51.4461], [29.7408, 51.53417], [29.54372, 51.48372], [29.49773, 51.39814], [29.42357, 51.4187], [29.32881, 51.37843], [29.25191, 51.49828], [29.25603, 51.57089], [29.20659, 51.56918], [29.16402, 51.64679], [29.1187, 51.65872], [28.99098, 51.56833], [28.95528, 51.59222], [28.81795, 51.55552], [28.76027, 51.48802], [28.78224, 51.45294], [28.75615, 51.41442], [28.73143, 51.46236], [28.69161, 51.44695], [28.64429, 51.5664], [28.47051, 51.59734], [28.37592, 51.54505], [28.23452, 51.66988], [28.10658, 51.57857], [27.95827, 51.56065], [27.91844, 51.61952], [27.85253, 51.62293], [27.76052, 51.47604], [27.67125, 51.50854], [27.71932, 51.60672], [27.55727, 51.63486], [27.51058, 51.5854], [27.47212, 51.61184], [27.24828, 51.60161], [27.26613, 51.65957], [27.20948, 51.66713], [27.20602, 51.77291], [26.99422, 51.76933], [26.9489, 51.73788], [26.80043, 51.75777], [26.69759, 51.82284], [26.46962, 51.80501], [26.39367, 51.87315], [26.19084, 51.86781], [26.00408, 51.92967], [25.83217, 51.92587], [25.80574, 51.94556], [25.73673, 51.91973], [25.46163, 51.92205], [25.20228, 51.97143], [24.98784, 51.91273], [24.37123, 51.88222], [24.29021, 51.80841], [24.3163, 51.75063], [24.13075, 51.66979], [23.99907, 51.58369], [23.8741, 51.59734], [23.91118, 51.63316], [23.7766, 51.66809], [23.60906, 51.62122], [23.6736, 51.50255], [23.62751, 51.50512], [23.69905, 51.40871], [23.63858, 51.32182], [23.80678, 51.18405], [23.90376, 51.07697], [23.92217, 51.00836], [24.04576, 50.90196], [24.14524, 50.86128], [24.0952, 50.83262], [23.99254, 50.83847], [23.95925, 50.79271], [24.0595, 50.71625], [24.0996, 50.60752], [24.07048, 50.5071], [24.03668, 50.44507], [23.99563, 50.41289], [23.79445, 50.40481], [23.71382, 50.38248], [23.67635, 50.33385], [23.28221, 50.0957], [22.99329, 49.84249], [22.83179, 49.69875], [22.80261, 49.69098], [22.78304, 49.65543], [22.64534, 49.53094], [22.69444, 49.49378], [22.748, 49.32759], [22.72009, 49.20288], [22.86336, 49.10513], [22.89122, 49.00725], [22.56155, 49.08865], [22.54338, 49.01424], [22.48296, 48.99172], [22.42934, 48.92857], [22.34151, 48.68893], [22.21379, 48.6218], [22.16023, 48.56548], [22.14689, 48.4005], [22.2083, 48.42534], [22.38133, 48.23726], [22.49806, 48.25189], [22.59007, 48.15121], [22.58733, 48.10813], [22.66835, 48.09162], [22.73427, 48.12005], [22.81804, 48.11363], [22.87847, 48.04665], [22.84276, 47.98602], [22.89849, 47.95851], [22.94301, 47.96672], [22.92241, 48.02002], [23.0158, 47.99338], [23.08858, 48.00716], [23.1133, 48.08061], [23.15999, 48.12188], [23.27397, 48.08245], [23.33577, 48.0237], [23.4979, 47.96858], [23.52803, 48.01818], [23.5653, 48.00499], [23.63894, 48.00293], [23.66262, 47.98786], [23.75188, 47.99705], [23.80904, 47.98142], [23.8602, 47.9329], [23.89352, 47.94512], [23.94192, 47.94868], [23.96337, 47.96672], [23.98553, 47.96076], [24.00801, 47.968], [24.02999, 47.95087], [24.06466, 47.95317], [24.11281, 47.91487], [24.22566, 47.90231], [24.34926, 47.9244], [24.43578, 47.97131], [24.61994, 47.95062], [24.70632, 47.84428], [24.81893, 47.82031], [24.88896, 47.7234], [25.11144, 47.75203], [25.23778, 47.89403], [25.63878, 47.94924], [25.77723, 47.93919], [26.05901, 47.9897], [26.17711, 47.99246], [26.33504, 48.18418], [26.55202, 48.22445], [26.62823, 48.25804], [26.6839, 48.35828], [26.79239, 48.29071], [26.82809, 48.31629], [26.71274, 48.40388], [26.85556, 48.41095], [26.93384, 48.36558], [27.03821, 48.37653], [27.0231, 48.42485], [27.08078, 48.43214], [27.13434, 48.37288], [27.27855, 48.37534], [27.32159, 48.4434], [27.37604, 48.44398], [27.37741, 48.41026], [27.44333, 48.41209], [27.46942, 48.454], [27.5889, 48.49224], [27.59027, 48.46311], [27.6658, 48.44034], [27.74422, 48.45926], [27.79225, 48.44244], [27.81902, 48.41874], [27.87533, 48.4037], [27.88391, 48.36699], [27.95883, 48.32368], [28.04527, 48.32661], [28.09873, 48.3124], [28.07504, 48.23494], [28.17666, 48.25963], [28.19314, 48.20749], [28.2856, 48.23202], [28.32508, 48.23384], [28.35519, 48.24957], [28.36996, 48.20543], [28.34912, 48.1787], [28.30586, 48.1597], [28.30609, 48.14018], [28.34009, 48.13147], [28.38712, 48.17567], [28.43701, 48.15832], [28.42454, 48.12047], [28.48428, 48.0737], [28.53921, 48.17453], [28.69896, 48.13106], [28.85232, 48.12506], [28.8414, 48.03392], [28.9306, 47.96255], [29.1723, 47.99013], [29.19839, 47.89261], [29.27804, 47.88893], [29.20663, 47.80367], [29.27255, 47.79953], [29.22242, 47.73607], [29.22414, 47.60012], [29.11743, 47.55001], [29.18603, 47.43387], [29.3261, 47.44664], [29.39889, 47.30179], [29.47854, 47.30366], [29.48678, 47.36043], [29.5733, 47.36508], [29.59665, 47.25521], [29.54996, 47.24962], [29.57696, 47.13581], [29.49732, 47.12878], [29.53044, 47.07851], [29.61038, 47.09932], [29.62137, 47.05069], [29.57056, 46.94766], [29.72986, 46.92234], [29.75458, 46.8604], [29.87405, 46.88199], [29.98814, 46.82358], [29.94522, 46.80055], [29.9743, 46.75325], [29.94409, 46.56002], [29.88916, 46.54302], [30.02511, 46.45132], [30.16794, 46.40967], [30.09103, 46.38694], [29.94114, 46.40114], [29.88329, 46.35851], [29.74496, 46.45605], [29.66359, 46.4215], [29.6763, 46.36041], [29.5939, 46.35472], [29.49914, 46.45889], [29.35357, 46.49505], [29.24886, 46.37912], [29.23547, 46.55435], [29.02409, 46.49582], [29.01241, 46.46177], [28.9306, 46.45699], [29.004, 46.31495], [28.98478, 46.31803], [28.94953, 46.25852], [29.06656, 46.19716], [28.94643, 46.09176], [29.00613, 46.04962], [28.98004, 46.00385], [28.74383, 45.96664], [28.78503, 45.83475], [28.69852, 45.81753], [28.70401, 45.78019], [28.52823, 45.73803], [28.47879, 45.66994], [28.51587, 45.6613], [28.54196, 45.58062], [28.49252, 45.56716], [28.51449, 45.49982], [28.43072, 45.48538], [28.41836, 45.51715], [28.30201, 45.54744], [28.21139, 45.46895], [28.28504, 45.43907], [28.34554, 45.32102], [28.5735, 45.24759], [28.71358, 45.22631], [28.78911, 45.24179], [28.81383, 45.3384], [28.94292, 45.28045], [28.96077, 45.33164], [29.24779, 45.43388], [29.42632, 45.44545], [29.59798, 45.38857], [29.68175, 45.26885], [29.65428, 45.25629], [29.69272, 45.19227], [30.04414, 45.08461], [31.62627, 45.50633], [33.54017, 46.0123], [33.59087, 46.06013], [33.57318, 46.10317]]]]
27447 groups: ["014", "202", "002", "UN"],
27449 callingCodes: ["256"]
27452 type: "MultiPolygon",
27453 coordinates: [[[[33.93107, -0.99298], [33.9264, -0.54188], [33.98449, -0.13079], [33.90936, 0.10581], [34.10067, 0.36372], [34.08727, 0.44713], [34.11408, 0.48884], [34.13493, 0.58118], [34.20196, 0.62289], [34.27345, 0.63182], [34.31516, 0.75693], [34.40041, 0.80266], [34.43349, 0.85254], [34.52369, 1.10692], [34.57427, 1.09868], [34.58029, 1.14712], [34.67562, 1.21265], [34.80223, 1.22754], [34.82606, 1.26626], [34.82606, 1.30944], [34.7918, 1.36752], [34.87819, 1.5596], [34.92734, 1.56109], [34.9899, 1.6668], [34.98692, 1.97348], [34.90947, 2.42447], [34.95267, 2.47209], [34.77244, 2.70272], [34.78137, 2.76223], [34.73967, 2.85447], [34.65774, 2.8753], [34.60114, 2.93034], [34.56242, 3.11478], [34.45815, 3.18319], [34.40006, 3.37949], [34.41794, 3.44342], [34.39112, 3.48802], [34.44922, 3.51627], [34.45815, 3.67385], [34.15429, 3.80464], [34.06046, 4.15235], [33.9873, 4.23316], [33.51264, 3.75068], [33.18356, 3.77812], [33.02852, 3.89296], [32.89746, 3.81339], [32.72021, 3.77327], [32.41337, 3.748], [32.20782, 3.6053], [32.19888, 3.50867], [32.08866, 3.53543], [32.08491, 3.56287], [32.05187, 3.589], [31.95907, 3.57408], [31.96205, 3.6499], [31.86821, 3.78664], [31.81459, 3.82083], [31.72075, 3.74354], [31.50776, 3.63652], [31.50478, 3.67814], [31.29476, 3.8015], [31.16666, 3.79853], [30.97601, 3.693], [30.85153, 3.48867], [30.94081, 3.50847], [30.93486, 3.40737], [30.84251, 3.26908], [30.77101, 3.04897], [30.8574, 2.9508], [30.8857, 2.83923], [30.75612, 2.5863], [30.74271, 2.43601], [30.83059, 2.42559], [30.91102, 2.33332], [30.96911, 2.41071], [31.06593, 2.35862], [31.07934, 2.30207], [31.12104, 2.27676], [31.1985, 2.29462], [31.20148, 2.2217], [31.28042, 2.17853], [31.30127, 2.11006], [30.48503, 1.21675], [30.24671, 1.14974], [30.22139, 0.99635], [30.1484, 0.89805], [29.98307, 0.84295], [29.95477, 0.64486], [29.97413, 0.52124], [29.87284, 0.39166], [29.81922, 0.16824], [29.77454, 0.16675], [29.7224, 0.07291], [29.72687, -0.08051], [29.65091, -0.46777], [29.67474, -0.47969], [29.67176, -0.55714], [29.62708, -0.71055], [29.63006, -0.8997], [29.58388, -0.89821], [29.59061, -1.39016], [29.82657, -1.31187], [29.912, -1.48269], [30.16369, -1.34303], [30.35212, -1.06896], [30.47194, -1.0555], [30.64166, -1.06601], [30.70631, -1.01175], [30.76635, -0.9852], [30.80408, -0.99911], [33.93107, -0.99298]]]]
27461 wikidata: "Q16645",
27462 nameEn: "United States Minor Outlying Islands",
27471 nameEn: "United Nations",
27472 level: "unitedNations",
27473 isoStatus: "excRes"
27483 nameEn: "United States of America"
27494 groups: ["005", "419", "019", "UN"],
27495 callingCodes: ["598"]
27498 type: "MultiPolygon",
27499 coordinates: [[[[-57.65132, -30.19229], [-57.61478, -30.25165], [-57.64859, -30.35095], [-57.89115, -30.49572], [-57.8024, -30.77193], [-57.89476, -30.95994], [-57.86729, -31.06352], [-57.9908, -31.34924], [-57.98127, -31.3872], [-58.07569, -31.44916], [-58.0023, -31.53084], [-58.00076, -31.65016], [-58.20252, -31.86966], [-58.10036, -32.25338], [-58.22362, -32.52416], [-58.1224, -32.98842], [-58.40475, -33.11777], [-58.44442, -33.84033], [-58.34425, -34.15035], [-57.83001, -34.69099], [-54.78916, -36.21945], [-52.83257, -34.01481], [-53.37138, -33.74313], [-53.39593, -33.75169], [-53.44031, -33.69344], [-53.52794, -33.68908], [-53.53459, -33.16843], [-53.1111, -32.71147], [-53.37671, -32.57005], [-53.39572, -32.58596], [-53.76024, -32.0751], [-54.17384, -31.86168], [-55.50821, -30.91349], [-55.50841, -30.9027], [-55.51862, -30.89828], [-55.52712, -30.89997], [-55.53276, -30.90218], [-55.53431, -30.89714], [-55.54572, -30.89051], [-55.55218, -30.88193], [-55.55373, -30.8732], [-55.5634, -30.8686], [-55.58866, -30.84117], [-55.87388, -31.05053], [-56.4619, -30.38457], [-56.4795, -30.3899], [-56.49267, -30.39471], [-56.90236, -30.02578], [-57.22502, -30.26121], [-57.65132, -30.19229]]]]
27508 nameEn: "Uzbekistan",
27509 groups: ["143", "142", "UN"],
27510 callingCodes: ["998"]
27513 type: "MultiPolygon",
27514 coordinates: [[[[65.85194, 42.85481], [65.53277, 43.31856], [65.18666, 43.48835], [64.96464, 43.74748], [64.53885, 43.56941], [63.34656, 43.64003], [62.01711, 43.51008], [61.01475, 44.41383], [58.59711, 45.58671], [55.97842, 44.99622], [55.97832, 44.99622], [55.97822, 44.99617], [55.97811, 44.99617], [55.97801, 44.99612], [55.97801, 44.99607], [55.97791, 44.99607], [55.9778, 44.99607], [55.9777, 44.99601], [55.9777, 44.99596], [55.9776, 44.99591], [55.97749, 44.99591], [55.97739, 44.99591], [55.97739, 44.99586], [55.97729, 44.99586], [55.97718, 44.99581], [55.97708, 44.99576], [55.97698, 44.9957], [55.97698, 44.99565], [55.97687, 44.9956], [55.97677, 44.9956], [55.97677, 44.99555], [55.97677, 44.9955], [55.97667, 44.99545], [55.97656, 44.99539], [55.97646, 44.99534], [55.97646, 44.99529], [55.97636, 44.99524], [55.97636, 44.99519], [55.97625, 44.99514], [55.97615, 44.99508], [55.97615, 44.99503], [55.97615, 44.99498], [55.97615, 44.99493], [55.97615, 44.99483], [55.97615, 44.99477], [55.97605, 44.99477], [55.97605, 44.99467], [55.97605, 44.99462], [55.97605, 44.99457], [55.97605, 44.99452], [55.97594, 44.99446], [55.97584, 44.99441], [55.97584, 44.99436], [55.97584, 44.99431], [55.97584, 44.99426], [55.97584, 44.99421], [55.97584, 44.99415], [55.97584, 44.99405], [55.97584, 44.994], [55.97584, 44.9939], [55.97584, 44.99384], [55.97584, 44.99374], [55.97584, 44.99369], [55.97584, 44.99359], [55.97584, 44.99353], [55.97584, 44.99348], [55.97584, 44.99343], [55.97584, 44.99338], [55.97584, 44.99328], [55.97584, 44.99322], [56.00314, 41.32584], [57.03423, 41.25435], [57.13796, 41.36625], [57.03359, 41.41777], [56.96218, 41.80383], [57.03633, 41.92043], [57.30275, 42.14076], [57.6296, 42.16519], [57.84932, 42.18555], [57.92897, 42.24047], [57.90975, 42.4374], [57.99214, 42.50021], [58.3492, 42.43335], [58.40688, 42.29535], [58.51674, 42.30348], [58.29427, 42.56497], [58.14321, 42.62159], [58.27504, 42.69632], [58.57991, 42.64988], [58.6266, 42.79314], [58.93422, 42.5407], [59.17317, 42.52248], [59.2955, 42.37064], [59.4341, 42.29738], [59.94633, 42.27655], [60.00539, 42.212], [59.96419, 42.1428], [60.04659, 42.08982], [60.0356, 42.01028], [59.95046, 41.97966], [60.33223, 41.75058], [60.08504, 41.80997], [60.06032, 41.76287], [60.18117, 41.60082], [60.06581, 41.4363], [60.5078, 41.21694], [61.03261, 41.25691], [61.22212, 41.14946], [61.33199, 41.14946], [61.39732, 41.19873], [61.4446, 41.29407], [61.87856, 41.12257], [62.11751, 40.58242], [62.34273, 40.43206], [62.43337, 39.98528], [63.6913, 39.27666], [63.70778, 39.22349], [64.19086, 38.95561], [64.32576, 38.98691], [65.55873, 38.29052], [65.83913, 38.25733], [66.24013, 38.16238], [66.41042, 38.02403], [66.56697, 38.0435], [66.67684, 37.96776], [66.53676, 37.80084], [66.52852, 37.58568], [66.65761, 37.45497], [66.52303, 37.39827], [66.55743, 37.35409], [66.64699, 37.32958], [66.95598, 37.40162], [67.08232, 37.35469], [67.13039, 37.27168], [67.2224, 37.24545], [67.2581, 37.17216], [67.51868, 37.26102], [67.78329, 37.1834], [67.8474, 37.31594], [67.81566, 37.43107], [68.12635, 37.93], [68.27159, 37.91477], [68.40343, 38.19484], [68.13289, 38.40822], [68.06274, 38.39435], [68.11366, 38.47169], [68.05873, 38.56087], [68.0807, 38.64136], [68.05598, 38.71641], [68.12877, 38.73677], [68.06948, 38.82115], [68.19743, 38.85985], [68.09704, 39.02589], [67.68915, 39.00775], [67.67833, 39.14479], [67.33226, 39.23739], [67.36522, 39.31287], [67.45998, 39.315], [67.46822, 39.46146], [67.39681, 39.52505], [67.46547, 39.53564], [67.44899, 39.57799], [67.62889, 39.60234], [67.70992, 39.66156], [68.12053, 39.56317], [68.54166, 39.53929], [68.61972, 39.68905], [68.63071, 39.85265], [68.88889, 39.87163], [68.93695, 39.91167], [68.84906, 40.04952], [68.96579, 40.06949], [69.01935, 40.11466], [69.01523, 40.15771], [68.62796, 40.07789], [68.52771, 40.11676], [68.5332, 40.14826], [68.77902, 40.20492], [68.79276, 40.17555], [68.84357, 40.18604], [68.85832, 40.20885], [69.04544, 40.22904], [69.15659, 40.2162], [69.2074, 40.21488], [69.30448, 40.18774], [69.30104, 40.24502], [69.25229, 40.26362], [69.24817, 40.30357], [69.30808, 40.2821], [69.32833, 40.29794], [69.33794, 40.34819], [69.30774, 40.36102], [69.28525, 40.41894], [69.27066, 40.49274], [69.21063, 40.54469], [69.2643, 40.57506], [69.3455, 40.57988], [69.32834, 40.70233], [69.38327, 40.7918], [69.53021, 40.77621], [69.59441, 40.70181], [69.69434, 40.62615], [70.36655, 40.90296], [70.38028, 41.02014], [70.45251, 41.04438], [70.80009, 40.72825], [70.49871, 40.52503], [70.32626, 40.45174], [70.37511, 40.38605], [70.57149, 40.3442], [70.56394, 40.26421], [70.62342, 40.17396], [70.8607, 40.217], [70.9818, 40.22392], [70.95789, 40.28761], [71.05901, 40.28765], [71.13042, 40.34106], [71.36663, 40.31593], [71.4246, 40.28619], [71.51215, 40.26943], [71.51549, 40.22986], [71.61725, 40.20615], [71.61931, 40.26775], [71.68386, 40.26984], [71.70569, 40.20391], [71.69621, 40.18492], [71.71719, 40.17886], [71.73054, 40.14818], [71.82646, 40.21872], [71.85002, 40.25647], [72.05464, 40.27586], [71.96401, 40.31907], [72.18648, 40.49893], [72.24368, 40.46091], [72.40346, 40.4007], [72.44191, 40.48222], [72.41513, 40.50856], [72.38384, 40.51535], [72.41714, 40.55736], [72.34406, 40.60144], [72.40517, 40.61917], [72.47795, 40.5532], [72.66713, 40.5219], [72.66713, 40.59076], [72.69579, 40.59778], [72.73995, 40.58409], [72.74768, 40.58051], [72.74862, 40.57131], [72.75982, 40.57273], [72.74894, 40.59592], [72.74866, 40.60873], [72.80137, 40.67856], [72.84754, 40.67229], [72.85372, 40.7116], [72.8722, 40.71111], [72.93296, 40.73089], [72.99133, 40.76457], [73.0612, 40.76678], [73.13412, 40.79122], [73.13267, 40.83512], [73.01869, 40.84681], [72.94454, 40.8094], [72.84291, 40.85512], [72.68157, 40.84942], [72.59136, 40.86947], [72.55109, 40.96046], [72.48742, 40.97136], [72.45206, 41.03018], [72.38511, 41.02785], [72.36138, 41.04384], [72.34757, 41.06104], [72.34026, 41.04539], [72.324, 41.03381], [72.18339, 40.99571], [72.17594, 41.02377], [72.21061, 41.05607], [72.1792, 41.10621], [72.14864, 41.13363], [72.17594, 41.15522], [72.16433, 41.16483], [72.10745, 41.15483], [72.07249, 41.11739], [71.85964, 41.19081], [71.91457, 41.2982], [71.83914, 41.3546], [71.76625, 41.4466], [71.71132, 41.43012], [71.73054, 41.54713], [71.65914, 41.49599], [71.6787, 41.42111], [71.57227, 41.29175], [71.46688, 41.31883], [71.43814, 41.19644], [71.46148, 41.13958], [71.40198, 41.09436], [71.34877, 41.16807], [71.27187, 41.11015], [71.25813, 41.18796], [71.11806, 41.15359], [71.02193, 41.19494], [70.9615, 41.16393], [70.86263, 41.23833], [70.77885, 41.24813], [70.78572, 41.36419], [70.67586, 41.47953], [70.48909, 41.40335], [70.17682, 41.5455], [70.69777, 41.92554], [71.28719, 42.18033], [71.13263, 42.28356], [70.94483, 42.26238], [69.49545, 41.545], [69.45751, 41.56863], [69.39485, 41.51518], [69.45081, 41.46246], [69.37468, 41.46555], [69.35554, 41.47211], [69.29778, 41.43673], [69.25059, 41.46693], [69.23332, 41.45847], [69.22671, 41.46298], [69.20439, 41.45391], [69.18528, 41.45175], [69.17701, 41.43769], [69.15137, 41.43078], [69.05006, 41.36183], [69.01308, 41.22804], [68.7217, 41.05025], [68.73945, 40.96989], [68.65662, 40.93861], [68.62221, 41.03019], [68.49983, 40.99669], [68.58444, 40.91447], [68.63, 40.59358], [68.49983, 40.56437], [67.96736, 40.83798], [68.1271, 41.0324], [68.08273, 41.08148], [67.98511, 41.02794], [67.9644, 41.14611], [66.69129, 41.1311], [66.53302, 41.87388], [66.00546, 41.94455], [66.09482, 42.93426], [65.85194, 42.85481]], [[70.68112, 40.90612], [70.6721, 40.90555], [70.57501, 40.98941], [70.54223, 40.98787], [70.56077, 41.00642], [70.6158, 40.97661], [70.68112, 40.90612]]], [[[71.21139, 40.03369], [71.12218, 40.03052], [71.06305, 40.1771], [71.00236, 40.18154], [71.01035, 40.05481], [71.11037, 40.01984], [71.11668, 39.99291], [71.09063, 39.99], [71.10501, 39.95568], [71.04979, 39.89808], [71.10531, 39.91354], [71.16101, 39.88423], [71.23067, 39.93581], [71.1427, 39.95026], [71.21139, 40.03369]]], [[[71.86463, 39.98598], [71.78838, 40.01404], [71.71511, 39.96348], [71.7504, 39.93701], [71.84316, 39.95582], [71.86463, 39.98598]]]]
27523 nameEn: "Vatican City",
27524 aliases: ["Holy See"],
27525 groups: ["039", "150"],
27526 callingCodes: ["379", "39 06"]
27529 type: "MultiPolygon",
27530 coordinates: [[[[12.45181, 41.90056], [12.45446, 41.90028], [12.45435, 41.90143], [12.45626, 41.90172], [12.45691, 41.90125], [12.4577, 41.90115], [12.45834, 41.90174], [12.45826, 41.90281], [12.45755, 41.9033], [12.45762, 41.9058], [12.45561, 41.90629], [12.45543, 41.90738], [12.45091, 41.90625], [12.44984, 41.90545], [12.44815, 41.90326], [12.44582, 41.90194], [12.44834, 41.90095], [12.45181, 41.90056]]]]
27539 nameEn: "St. Vincent and the Grenadines",
27541 groups: ["029", "003", "419", "019", "UN"],
27543 roadSpeedUnit: "mph",
27544 callingCodes: ["1 784"]
27547 type: "MultiPolygon",
27548 coordinates: [[[[-62.64026, 12.69984], [-59.94058, 12.34011], [-61.69315, 14.26451], [-62.64026, 12.69984]]]]
27557 nameEn: "Venezuela",
27559 groups: ["005", "419", "019", "UN"],
27560 callingCodes: ["58"]
27563 type: "MultiPolygon",
27564 coordinates: [[[[-71.22331, 13.01387], [-70.92579, 11.96275], [-71.3275, 11.85], [-71.9675, 11.65536], [-72.24983, 11.14138], [-72.4767, 11.1117], [-72.88002, 10.44309], [-72.98085, 9.85253], [-73.36905, 9.16636], [-73.02119, 9.27584], [-72.94052, 9.10663], [-72.77415, 9.10165], [-72.65474, 8.61428], [-72.4042, 8.36513], [-72.36987, 8.19976], [-72.35163, 8.01163], [-72.39137, 8.03534], [-72.47213, 7.96106], [-72.48801, 7.94329], [-72.48183, 7.92909], [-72.47042, 7.92306], [-72.45806, 7.91141], [-72.46183, 7.90682], [-72.44454, 7.86031], [-72.46763, 7.79518], [-72.47827, 7.65604], [-72.45321, 7.57232], [-72.47415, 7.48928], [-72.43132, 7.40034], [-72.19437, 7.37034], [-72.04895, 7.03837], [-71.82441, 7.04314], [-71.44118, 7.02116], [-71.42212, 7.03854], [-71.37234, 7.01588], [-71.03941, 6.98163], [-70.7596, 7.09799], [-70.10716, 6.96516], [-69.41843, 6.1072], [-67.60654, 6.2891], [-67.4625, 6.20625], [-67.43513, 5.98835], [-67.58558, 5.84537], [-67.63914, 5.64963], [-67.59141, 5.5369], [-67.83341, 5.31104], [-67.85358, 4.53249], [-67.62671, 3.74303], [-67.50067, 3.75812], [-67.30945, 3.38393], [-67.85862, 2.86727], [-67.85862, 2.79173], [-67.65696, 2.81691], [-67.21967, 2.35778], [-66.85795, 1.22998], [-66.28507, 0.74585], [-65.6727, 1.01353], [-65.50158, 0.92086], [-65.57288, 0.62856], [-65.11657, 1.12046], [-64.38932, 1.5125], [-64.34654, 1.35569], [-64.08274, 1.64792], [-64.06135, 1.94722], [-63.39827, 2.16098], [-63.39114, 2.4317], [-64.0257, 2.48156], [-64.02908, 2.79797], [-64.48379, 3.7879], [-64.84028, 4.24665], [-64.72977, 4.28931], [-64.57648, 4.12576], [-64.14512, 4.12932], [-63.99183, 3.90172], [-63.86082, 3.94796], [-63.70218, 3.91417], [-63.67099, 4.01731], [-63.50611, 3.83592], [-63.42233, 3.89995], [-63.4464, 3.9693], [-63.21111, 3.96219], [-62.98296, 3.59935], [-62.7655, 3.73099], [-62.74411, 4.03331], [-62.57656, 4.04754], [-62.44822, 4.18621], [-62.13094, 4.08309], [-61.54629, 4.2822], [-61.48569, 4.43149], [-61.29675, 4.44216], [-61.31457, 4.54167], [-61.15703, 4.49839], [-60.98303, 4.54167], [-60.86539, 4.70512], [-60.5802, 4.94312], [-60.73204, 5.20931], [-61.4041, 5.95304], [-61.15058, 6.19558], [-61.20762, 6.58174], [-61.13632, 6.70922], [-60.54873, 6.8631], [-60.39419, 6.94847], [-60.28074, 7.1162], [-60.44116, 7.20817], [-60.54098, 7.14804], [-60.63367, 7.25061], [-60.59802, 7.33194], [-60.71923, 7.55817], [-60.64793, 7.56877], [-60.51959, 7.83373], [-60.38056, 7.8302], [-60.02407, 8.04557], [-59.97059, 8.20791], [-59.83156, 8.23261], [-59.80661, 8.28906], [-59.85562, 8.35213], [-59.98508, 8.53046], [-59.54058, 8.6862], [-60.89962, 9.81445], [-62.08693, 10.04435], [-61.62505, 11.18974], [-63.73917, 11.92623], [-63.19938, 16.44103], [-67.89186, 12.4116], [-68.01417, 11.77722], [-68.33524, 11.78151], [-68.99639, 11.79035], [-71.22331, 13.01387]]]]
27572 wikidata: "Q25305",
27573 nameEn: "British Virgin Islands",
27575 groups: ["BOTS", "029", "003", "419", "019", "UN"],
27577 roadSpeedUnit: "mph",
27578 roadHeightUnit: "ft",
27579 callingCodes: ["1 284"]
27582 type: "MultiPolygon",
27583 coordinates: [[[[-64.47127, 17.55688], [-63.88746, 19.15706], [-65.02435, 18.73231], [-64.86027, 18.39056], [-64.64673, 18.36549], [-64.47127, 17.55688]]]]
27591 wikidata: "Q11703",
27592 nameEn: "United States Virgin Islands",
27593 aliases: ["US-VI"],
27595 groups: ["Q1352230", "029", "003", "419", "019", "UN"],
27597 roadSpeedUnit: "mph",
27598 roadHeightUnit: "ft",
27599 callingCodes: ["1 340"]
27602 type: "MultiPolygon",
27603 coordinates: [[[[-65.02435, 18.73231], [-65.27974, 17.56928], [-64.47127, 17.55688], [-64.64673, 18.36549], [-64.86027, 18.39056], [-65.02435, 18.73231]]]]
27613 groups: ["035", "142", "UN"],
27614 callingCodes: ["84"]
27617 type: "MultiPolygon",
27618 coordinates: [[[[108.10003, 21.47338], [108.0569, 21.53604], [108.02926, 21.54997], [107.97932, 21.54503], [107.97383, 21.53961], [107.97074, 21.54072], [107.96774, 21.53601], [107.95232, 21.5388], [107.92652, 21.58906], [107.90006, 21.5905], [107.86114, 21.65128], [107.80355, 21.66141], [107.66967, 21.60787], [107.56537, 21.61945], [107.54047, 21.5934], [107.49065, 21.59774], [107.49532, 21.62958], [107.47197, 21.6672], [107.41593, 21.64839], [107.38636, 21.59774], [107.35989, 21.60063], [107.35834, 21.6672], [107.29296, 21.74674], [107.24625, 21.7077], [107.20734, 21.71493], [107.10771, 21.79879], [107.02615, 21.81981], [107.00964, 21.85948], [107.06101, 21.88982], [107.05634, 21.92303], [106.99252, 21.95191], [106.97228, 21.92592], [106.92714, 21.93459], [106.9178, 21.97357], [106.81038, 21.97934], [106.74345, 22.00965], [106.72551, 21.97923], [106.69276, 21.96013], [106.68274, 21.99811], [106.70142, 22.02409], [106.6983, 22.15102], [106.67495, 22.1885], [106.69986, 22.22309], [106.6516, 22.33977], [106.55976, 22.34841], [106.57221, 22.37], [106.55665, 22.46498], [106.58395, 22.474], [106.61269, 22.60301], [106.65316, 22.5757], [106.71698, 22.58432], [106.72321, 22.63606], [106.76293, 22.73491], [106.82404, 22.7881], [106.83685, 22.8098], [106.81271, 22.8226], [106.78422, 22.81532], [106.71128, 22.85982], [106.71387, 22.88296], [106.6734, 22.89587], [106.6516, 22.86862], [106.60179, 22.92884], [106.55976, 22.92311], [106.51306, 22.94891], [106.49749, 22.91164], [106.34961, 22.86718], [106.27022, 22.87722], [106.19705, 22.98475], [106.00179, 22.99049], [105.99568, 22.94178], [105.90119, 22.94168], [105.8726, 22.92756], [105.72382, 23.06641], [105.57594, 23.075], [105.56037, 23.16806], [105.49966, 23.20669], [105.42805, 23.30824], [105.40782, 23.28107], [105.32376, 23.39684], [105.22569, 23.27249], [105.17276, 23.28679], [105.11672, 23.25247], [105.07002, 23.26248], [104.98712, 23.19176], [104.96532, 23.20463], [104.9486, 23.17235], [104.91435, 23.18666], [104.87992, 23.17141], [104.87382, 23.12854], [104.79478, 23.12934], [104.8334, 23.01484], [104.86765, 22.95178], [104.84942, 22.93631], [104.77114, 22.90017], [104.72755, 22.81984], [104.65283, 22.83419], [104.60457, 22.81841], [104.58122, 22.85571], [104.47225, 22.75813], [104.35593, 22.69353], [104.25683, 22.76534], [104.27084, 22.8457], [104.11384, 22.80363], [104.03734, 22.72945], [104.01088, 22.51823], [103.99247, 22.51958], [103.97384, 22.50634], [103.96783, 22.51173], [103.96352, 22.50584], [103.95191, 22.5134], [103.94513, 22.52553], [103.93286, 22.52703], [103.87904, 22.56683], [103.64506, 22.79979], [103.56255, 22.69499], [103.57812, 22.65764], [103.52675, 22.59155], [103.43646, 22.70648], [103.43179, 22.75816], [103.32282, 22.8127], [103.28079, 22.68063], [103.18895, 22.64471], [103.15782, 22.59873], [103.17961, 22.55705], [103.07843, 22.50097], [103.0722, 22.44775], [102.9321, 22.48659], [102.8636, 22.60735], [102.60675, 22.73376], [102.57095, 22.7036], [102.51802, 22.77969], [102.46665, 22.77108], [102.42618, 22.69212], [102.38415, 22.67919], [102.41061, 22.64184], [102.25339, 22.4607], [102.26428, 22.41321], [102.16621, 22.43336], [102.14099, 22.40092], [102.18712, 22.30403], [102.51734, 22.02676], [102.49092, 21.99002], [102.62301, 21.91447], [102.67145, 21.65894], [102.74189, 21.66713], [102.82115, 21.73667], [102.81894, 21.83888], [102.85637, 21.84501], [102.86077, 21.71213], [102.97965, 21.74076], [102.98846, 21.58936], [102.86297, 21.4255], [102.94223, 21.46034], [102.88939, 21.3107], [102.80794, 21.25736], [102.89825, 21.24707], [102.97745, 21.05821], [103.03469, 21.05821], [103.12055, 20.89994], [103.21497, 20.89832], [103.38032, 20.79501], [103.45737, 20.82382], [103.68633, 20.66324], [103.73478, 20.6669], [103.82282, 20.8732], [103.98024, 20.91531], [104.11121, 20.96779], [104.27412, 20.91433], [104.63957, 20.6653], [104.38199, 20.47155], [104.40621, 20.3849], [104.47886, 20.37459], [104.66158, 20.47774], [104.72102, 20.40554], [104.62195, 20.36633], [104.61315, 20.24452], [104.86852, 20.14121], [104.91695, 20.15567], [104.9874, 20.09573], [104.8465, 19.91783], [104.8355, 19.80395], [104.68359, 19.72729], [104.64837, 19.62365], [104.53169, 19.61743], [104.41281, 19.70035], [104.23229, 19.70242], [104.06498, 19.66926], [104.05617, 19.61743], [104.10832, 19.51575], [104.06058, 19.43484], [103.87125, 19.31854], [104.5361, 18.97747], [104.64617, 18.85668], [105.12829, 18.70453], [105.19654, 18.64196], [105.1327, 18.58355], [105.10408, 18.43533], [105.15942, 18.38691], [105.38366, 18.15315], [105.46292, 18.22008], [105.64784, 17.96687], [105.60381, 17.89356], [105.76612, 17.67147], [105.85744, 17.63221], [106.09019, 17.36399], [106.18991, 17.28227], [106.24444, 17.24714], [106.29287, 17.3018], [106.31929, 17.20509], [106.43597, 17.01362], [106.50862, 16.9673], [106.55045, 17.0031], [106.54824, 16.92729], [106.51963, 16.92097], [106.52183, 16.87884], [106.55265, 16.86831], [106.55485, 16.68704], [106.59013, 16.62259], [106.58267, 16.6012], [106.61477, 16.60713], [106.66052, 16.56892], [106.65832, 16.47816], [106.74418, 16.41904], [106.84104, 16.55415], [106.88727, 16.52671], [106.88067, 16.43594], [106.96638, 16.34938], [106.97385, 16.30204], [107.02597, 16.31132], [107.09091, 16.3092], [107.15035, 16.26271], [107.14595, 16.17816], [107.25822, 16.13587], [107.33968, 16.05549], [107.44975, 16.08511], [107.46296, 16.01106], [107.39471, 15.88829], [107.34188, 15.89464], [107.21419, 15.83747], [107.21859, 15.74638], [107.27143, 15.71459], [107.27583, 15.62769], [107.34408, 15.62345], [107.3815, 15.49832], [107.50699, 15.48771], [107.53341, 15.40496], [107.62367, 15.42193], [107.60605, 15.37524], [107.62587, 15.2266], [107.58844, 15.20111], [107.61926, 15.13949], [107.61486, 15.0566], [107.46516, 15.00982], [107.48277, 14.93751], [107.59285, 14.87795], [107.51579, 14.79282], [107.54361, 14.69092], [107.55371, 14.628], [107.52102, 14.59034], [107.52569, 14.54665], [107.48521, 14.40346], [107.44941, 14.41552], [107.39493, 14.32655], [107.40427, 14.24509], [107.33577, 14.11832], [107.37158, 14.07906], [107.35757, 14.02319], [107.38247, 13.99147], [107.44318, 13.99751], [107.46498, 13.91593], [107.45252, 13.78897], [107.53503, 13.73908], [107.61909, 13.52577], [107.62843, 13.3668], [107.49144, 13.01215], [107.49611, 12.88926], [107.55993, 12.7982], [107.5755, 12.52177], [107.55059, 12.36824], [107.4463, 12.29373], [107.42917, 12.24657], [107.34511, 12.33327], [107.15831, 12.27547], [106.99953, 12.08983], [106.92325, 12.06548], [106.79405, 12.0807], [106.70687, 11.96956], [106.4111, 11.97413], [106.4687, 11.86751], [106.44068, 11.86294], [106.44535, 11.8279], [106.41577, 11.76999], [106.45158, 11.68616], [106.44691, 11.66787], [106.37219, 11.69836], [106.30525, 11.67549], [106.26478, 11.72122], [106.18539, 11.75171], [106.13158, 11.73283], [106.06708, 11.77761], [106.02038, 11.77457], [106.00792, 11.7197], [105.95188, 11.63738], [105.88962, 11.67854], [105.8507, 11.66635], [105.80867, 11.60536], [105.81645, 11.56876], [105.87328, 11.55953], [105.88962, 11.43605], [105.86782, 11.28343], [106.10444, 11.07879], [106.1527, 11.10476], [106.1757, 11.07301], [106.20095, 10.97795], [106.14301, 10.98176], [106.18539, 10.79451], [106.06708, 10.8098], [105.94535, 10.9168], [105.93403, 10.83853], [105.84603, 10.85873], [105.86376, 10.89839], [105.77751, 11.03671], [105.50045, 10.94586], [105.42884, 10.96878], [105.34011, 10.86179], [105.11449, 10.96332], [105.08326, 10.95656], [105.02722, 10.89236], [105.09571, 10.72722], [104.95094, 10.64003], [104.87933, 10.52833], [104.59018, 10.53073], [104.49869, 10.4057], [104.47963, 10.43046], [104.43778, 10.42386], [103.99198, 10.48391], [102.47649, 9.66162], [104.81582, 8.03101], [109.55486, 8.10026], [111.60491, 13.57105], [108.00365, 17.98159], [108.10003, 21.47338]]]]
27628 groups: ["054", "009", "UN"],
27629 callingCodes: ["678"]
27632 type: "MultiPolygon",
27633 coordinates: [[[[156.73836, -14.50464], [174.245, -23.1974], [172.71443, -12.01327], [156.73836, -14.50464]]]]
27641 wikidata: "Q35555",
27642 nameEn: "Wallis and Futuna",
27644 groups: ["Q1451600", "061", "009", "UN"],
27645 callingCodes: ["681"]
27648 type: "MultiPolygon",
27649 coordinates: [[[[-178.66551, -14.32452], [-176.76826, -14.95183], [-175.59809, -12.61507], [-178.66551, -14.32452]]]]
27659 groups: ["061", "009", "UN"],
27661 callingCodes: ["685"]
27664 type: "MultiPolygon",
27665 coordinates: [[[[-173.74402, -14.26669], [-170.99605, -15.1275], [-171.39864, -10.21587], [-173.74402, -14.26669]]]]
27675 groups: ["039", "150"],
27676 isoStatus: "usrAssn",
27677 callingCodes: ["383"]
27680 type: "MultiPolygon",
27681 coordinates: [[[[21.39045, 42.74888], [21.44047, 42.87276], [21.36941, 42.87397], [21.32974, 42.90424], [21.2719, 42.8994], [21.23534, 42.95523], [21.23877, 43.00848], [21.2041, 43.02277], [21.16734, 42.99694], [21.14465, 43.11089], [21.08952, 43.13471], [21.05378, 43.10707], [21.00749, 43.13984], [20.96287, 43.12416], [20.83727, 43.17842], [20.88685, 43.21697], [20.82145, 43.26769], [20.73811, 43.25068], [20.68688, 43.21335], [20.59929, 43.20492], [20.69515, 43.09641], [20.64557, 43.00826], [20.59929, 43.01067], [20.48692, 42.93208], [20.53484, 42.8885], [20.43734, 42.83157], [20.40594, 42.84853], [20.35692, 42.8335], [20.27869, 42.81945], [20.2539, 42.76245], [20.04898, 42.77701], [20.02088, 42.74789], [20.02915, 42.71147], [20.0969, 42.65559], [20.07761, 42.55582], [20.17127, 42.50469], [20.21797, 42.41237], [20.24399, 42.32168], [20.34479, 42.32656], [20.3819, 42.3029], [20.48857, 42.25444], [20.56955, 42.12097], [20.55633, 42.08173], [20.59434, 42.03879], [20.63069, 41.94913], [20.57946, 41.91593], [20.59524, 41.8818], [20.68523, 41.85318], [20.76786, 41.91839], [20.75464, 42.05229], [21.11491, 42.20794], [21.16614, 42.19815], [21.22728, 42.08909], [21.31983, 42.10993], [21.29913, 42.13954], [21.30496, 42.1418], [21.38428, 42.24465], [21.43882, 42.23609], [21.43882, 42.2789], [21.50823, 42.27156], [21.52145, 42.24465], [21.58992, 42.25915], [21.56772, 42.30946], [21.5264, 42.33634], [21.53467, 42.36809], [21.57021, 42.3647], [21.59029, 42.38042], [21.62887, 42.37664], [21.64209, 42.41081], [21.62556, 42.45106], [21.7035, 42.51899], [21.70522, 42.54176], [21.7327, 42.55041], [21.75672, 42.62695], [21.79413, 42.65923], [21.75025, 42.70125], [21.6626, 42.67813], [21.58755, 42.70418], [21.59154, 42.72643], [21.47498, 42.74695], [21.39045, 42.74888]]]]
27691 groups: ["145", "142", "UN"],
27692 callingCodes: ["967"]
27695 type: "MultiPolygon",
27696 coordinates: [[[[57.49095, 8.14549], [52.81185, 17.28568], [52.74267, 17.29519], [52.78009, 17.35124], [52.00311, 19.00083], [49.04884, 18.59899], [48.19996, 18.20584], [47.58351, 17.50366], [47.48245, 17.10808], [47.00571, 16.94765], [46.76494, 17.29151], [46.31018, 17.20464], [44.50126, 17.47475], [43.70631, 17.35762], [43.43005, 17.56148], [43.29185, 17.53224], [43.22533, 17.38343], [43.32653, 17.31179], [43.20156, 17.25901], [43.17787, 17.14717], [43.23967, 17.03428], [43.18233, 17.02673], [43.1813, 16.98438], [43.19328, 16.94703], [43.1398, 16.90696], [43.18338, 16.84852], [43.22012, 16.83932], [43.22956, 16.80613], [43.24801, 16.80613], [43.26303, 16.79479], [43.25857, 16.75304], [43.21325, 16.74416], [43.22066, 16.65179], [43.15274, 16.67248], [43.11601, 16.53166], [42.97215, 16.51093], [42.94351, 16.49467], [42.94625, 16.39721], [42.76801, 16.40371], [42.15205, 16.40211], [40.99158, 15.81743], [43.29075, 12.79154], [43.32909, 12.59711], [43.90659, 12.3823], [51.12877, 12.56479], [57.49095, 8.14549]]]]
27704 wikidata: "Q17063",
27707 groups: ["Q3320166", "EU", "014", "202", "002", "UN"],
27708 callingCodes: ["262"]
27711 type: "MultiPolygon",
27712 coordinates: [[[[43.28731, -13.97126], [45.54824, -13.22353], [45.4971, -11.75965], [43.28731, -13.97126]]]]
27721 nameEn: "South Africa",
27722 groups: ["018", "202", "002", "UN"],
27724 callingCodes: ["27"]
27727 type: "MultiPolygon",
27728 coordinates: [[[[31.30611, -22.422], [31.16344, -22.32599], [31.08932, -22.34884], [30.86696, -22.28907], [30.6294, -22.32599], [30.48686, -22.31368], [30.38614, -22.34533], [30.28351, -22.35587], [30.2265, -22.2961], [30.13147, -22.30841], [29.92242, -22.19408], [29.76848, -22.14128], [29.64609, -22.12917], [29.37703, -22.19581], [29.21955, -22.17771], [29.18974, -22.18599], [29.15268, -22.21399], [29.10881, -22.21202], [29.0151, -22.22907], [28.91889, -22.44299], [28.63287, -22.55887], [28.34874, -22.5694], [28.04562, -22.8394], [28.04752, -22.90243], [27.93729, -22.96194], [27.93539, -23.04941], [27.74154, -23.2137], [27.6066, -23.21894], [27.52393, -23.37952], [27.33768, -23.40917], [26.99749, -23.65486], [26.84165, -24.24885], [26.51667, -24.47219], [26.46346, -24.60358], [26.39409, -24.63468], [25.8515, -24.75727], [25.84295, -24.78661], [25.88571, -24.87802], [25.72702, -25.25503], [25.69661, -25.29284], [25.6643, -25.4491], [25.58543, -25.6343], [25.33076, -25.76616], [25.12266, -25.75931], [25.01718, -25.72507], [24.8946, -25.80723], [24.67319, -25.81749], [24.44703, -25.73021], [24.36531, -25.773], [24.18287, -25.62916], [23.9244, -25.64286], [23.47588, -25.29971], [23.03497, -25.29971], [22.86012, -25.50572], [22.70808, -25.99186], [22.56365, -26.19668], [22.41921, -26.23078], [22.21206, -26.3773], [22.06192, -26.61882], [21.90703, -26.66808], [21.83291, -26.65959], [21.77114, -26.69015], [21.7854, -26.79199], [21.69322, -26.86152], [21.37869, -26.82083], [21.13353, -26.86661], [20.87031, -26.80047], [20.68596, -26.9039], [20.63275, -26.78181], [20.61754, -26.4692], [20.86081, -26.14892], [20.64795, -25.47827], [20.29826, -24.94869], [20.03678, -24.81004], [20.02809, -24.78725], [19.99817, -24.76768], [19.99882, -28.42622], [18.99885, -28.89165], [17.4579, -28.68718], [17.15405, -28.08573], [16.90446, -28.057], [16.59922, -28.53246], [16.46592, -28.57126], [16.45332, -28.63117], [12.51595, -32.27486], [38.88176, -48.03306], [34.51034, -26.91792], [32.35222, -26.86027], [32.29584, -26.852], [32.22302, -26.84136], [32.19409, -26.84032], [32.13315, -26.84345], [32.09664, -26.80721], [32.00893, -26.8096], [31.97463, -27.11057], [31.97592, -27.31675], [31.49834, -27.31549], [31.15027, -27.20151], [30.96088, -27.0245], [30.97757, -26.92706], [30.88826, -26.79622], [30.81101, -26.84722], [30.78927, -26.48271], [30.95819, -26.26303], [31.13073, -25.91558], [31.31237, -25.7431], [31.4175, -25.71886], [31.86881, -25.99973], [31.974, -25.95387], [31.92649, -25.84216], [32.00631, -25.65044], [31.97875, -25.46356], [32.01676, -25.38117], [32.03196, -25.10785], [31.9835, -24.29983], [31.90368, -24.18892], [31.87707, -23.95293], [31.77445, -23.90082], [31.70223, -23.72695], [31.67942, -23.60858], [31.56539, -23.47268], [31.55779, -23.176], [31.30611, -22.422]], [[29.33204, -29.45598], [29.28545, -29.58456], [29.12553, -29.76266], [29.16548, -29.91706], [28.9338, -30.05072], [28.80222, -30.10579], [28.68627, -30.12885], [28.399, -30.1592], [28.2319, -30.28476], [28.12073, -30.68072], [27.74814, -30.60635], [27.69467, -30.55862], [27.67819, -30.53437], [27.6521, -30.51707], [27.62137, -30.50509], [27.56781, -30.44562], [27.56901, -30.42504], [27.45452, -30.32239], [27.38108, -30.33456], [27.36649, -30.27246], [27.37293, -30.19401], [27.40778, -30.14577], [27.32555, -30.14785], [27.29603, -30.05473], [27.22719, -30.00718], [27.09489, -29.72796], [27.01016, -29.65439], [27.33464, -29.48161], [27.4358, -29.33465], [27.47254, -29.31968], [27.45125, -29.29708], [27.48679, -29.29349], [27.54258, -29.25575], [27.5158, -29.2261], [27.55974, -29.18954], [27.75458, -28.89839], [27.8907, -28.91612], [27.88933, -28.88156], [27.9392, -28.84864], [27.98675, -28.8787], [28.02503, -28.85991], [28.1317, -28.7293], [28.2348, -28.69471], [28.30518, -28.69531], [28.40612, -28.6215], [28.65091, -28.57025], [28.68043, -28.58744], [29.40524, -29.21246], [29.44883, -29.3772], [29.33204, -29.45598]]]]
27738 groups: ["014", "202", "002", "UN"],
27740 callingCodes: ["260"]
27743 type: "MultiPolygon",
27744 coordinates: [[[[32.95389, -9.40138], [32.76233, -9.31963], [32.75611, -9.28583], [32.53661, -9.24281], [32.49147, -9.14754], [32.43543, -9.11988], [32.25486, -9.13371], [32.16146, -9.05993], [32.08206, -9.04609], [31.98866, -9.07069], [31.94196, -9.02303], [31.94663, -8.93846], [31.81587, -8.88618], [31.71158, -8.91386], [31.57147, -8.81388], [31.57147, -8.70619], [31.37533, -8.60769], [31.00796, -8.58615], [30.79243, -8.27382], [28.88917, -8.4831], [28.9711, -8.66935], [28.38526, -9.23393], [28.36562, -9.30091], [28.52636, -9.35379], [28.51627, -9.44726], [28.56208, -9.49122], [28.68532, -9.78], [28.62795, -9.92942], [28.65032, -10.65133], [28.37241, -11.57848], [28.48357, -11.87532], [29.18592, -12.37921], [29.4992, -12.43843], [29.48404, -12.23604], [29.8139, -12.14898], [29.81551, -13.44683], [29.65078, -13.41844], [29.60531, -13.21685], [29.01918, -13.41353], [28.33199, -12.41375], [27.59932, -12.22123], [27.21025, -11.76157], [27.22541, -11.60323], [27.04351, -11.61312], [26.88687, -12.01868], [26.01777, -11.91488], [25.33058, -11.65767], [25.34069, -11.19707], [24.42612, -11.44975], [24.34528, -11.06816], [24.00027, -10.89356], [24.02603, -11.15368], [23.98804, -12.13149], [24.06672, -12.29058], [23.90937, -12.844], [24.03339, -12.99091], [21.97988, -13.00148], [22.00323, -16.18028], [22.17217, -16.50269], [23.20038, -17.47563], [23.47474, -17.62877], [24.23619, -17.47489], [24.32811, -17.49082], [24.38712, -17.46818], [24.5621, -17.52963], [24.70864, -17.49501], [25.00198, -17.58221], [25.26433, -17.79571], [25.51646, -17.86232], [25.6827, -17.81987], [25.85738, -17.91403], [25.85892, -17.97726], [26.08925, -17.98168], [26.0908, -17.93021], [26.21601, -17.88608], [26.55918, -17.99638], [26.68403, -18.07411], [26.74314, -18.0199], [26.89926, -17.98756], [27.14196, -17.81398], [27.30736, -17.60487], [27.61377, -17.34378], [27.62795, -17.24365], [27.83141, -16.96274], [28.73725, -16.5528], [28.76199, -16.51575], [28.81454, -16.48611], [28.8501, -16.04537], [28.9243, -15.93987], [29.01298, -15.93805], [29.21955, -15.76589], [29.4437, -15.68702], [29.8317, -15.6126], [30.35574, -15.6513], [30.41902, -15.62269], [30.22098, -14.99447], [33.24249, -14.00019], [33.16749, -13.93992], [33.07568, -13.98447], [33.02977, -14.05022], [32.99042, -13.95689], [32.88985, -13.82956], [32.79015, -13.80755], [32.76962, -13.77224], [32.84528, -13.71576], [32.7828, -13.64805], [32.68654, -13.64268], [32.66468, -13.60019], [32.68436, -13.55769], [32.73683, -13.57682], [32.84176, -13.52794], [32.86113, -13.47292], [33.0078, -13.19492], [32.98289, -13.12671], [33.02181, -12.88707], [32.96733, -12.88251], [32.94397, -12.76868], [33.05917, -12.59554], [33.18837, -12.61377], [33.28177, -12.54692], [33.37517, -12.54085], [33.54485, -12.35996], [33.47636, -12.32498], [33.3705, -12.34931], [33.25998, -12.14242], [33.33937, -11.91252], [33.32692, -11.59248], [33.24252, -11.59302], [33.23663, -11.40637], [33.29267, -11.43536], [33.29267, -11.3789], [33.39697, -11.15296], [33.25998, -10.88862], [33.28022, -10.84428], [33.47636, -10.78465], [33.70675, -10.56896], [33.54797, -10.36077], [33.53863, -10.20148], [33.31297, -10.05133], [33.37902, -9.9104], [33.36581, -9.81063], [33.31517, -9.82364], [33.2095, -9.61099], [33.12144, -9.58929], [33.10163, -9.66525], [33.05485, -9.61316], [33.00256, -9.63053], [33.00476, -9.5133], [32.95389, -9.40138]]]]
27753 nameEn: "Zimbabwe",
27754 groups: ["014", "202", "002", "UN"],
27756 callingCodes: ["263"]
27759 type: "MultiPolygon",
27760 coordinates: [[[[30.41902, -15.62269], [30.35574, -15.6513], [29.8317, -15.6126], [29.4437, -15.68702], [29.21955, -15.76589], [29.01298, -15.93805], [28.9243, -15.93987], [28.8501, -16.04537], [28.81454, -16.48611], [28.76199, -16.51575], [28.73725, -16.5528], [27.83141, -16.96274], [27.62795, -17.24365], [27.61377, -17.34378], [27.30736, -17.60487], [27.14196, -17.81398], [26.89926, -17.98756], [26.74314, -18.0199], [26.68403, -18.07411], [26.55918, -17.99638], [26.21601, -17.88608], [26.0908, -17.93021], [26.08925, -17.98168], [25.85892, -17.97726], [25.85738, -17.91403], [25.6827, -17.81987], [25.51646, -17.86232], [25.26433, -17.79571], [25.23909, -17.90832], [25.31799, -18.07091], [25.39972, -18.12691], [25.53465, -18.39041], [25.68859, -18.56165], [25.79217, -18.6355], [25.82353, -18.82808], [25.94326, -18.90362], [25.99837, -19.02943], [25.96226, -19.08152], [26.17227, -19.53709], [26.72246, -19.92707], [27.21278, -20.08244], [27.29831, -20.28935], [27.28865, -20.49873], [27.69361, -20.48531], [27.72972, -20.51735], [27.69171, -21.08409], [27.91407, -21.31621], [28.01669, -21.57624], [28.29416, -21.59037], [28.49942, -21.66634], [28.58114, -21.63455], [29.07763, -21.81877], [29.04023, -21.85864], [29.02191, -21.90647], [29.02191, -21.95665], [29.04108, -22.00563], [29.08495, -22.04867], [29.14501, -22.07275], [29.1974, -22.07472], [29.24648, -22.05967], [29.3533, -22.18363], [29.37703, -22.19581], [29.64609, -22.12917], [29.76848, -22.14128], [29.92242, -22.19408], [30.13147, -22.30841], [30.2265, -22.2961], [30.28351, -22.35587], [30.38614, -22.34533], [30.48686, -22.31368], [30.6294, -22.32599], [30.86696, -22.28907], [31.08932, -22.34884], [31.16344, -22.32599], [31.30611, -22.422], [31.38336, -22.36919], [32.41234, -21.31246], [32.48236, -21.32873], [32.37115, -21.133], [32.51644, -20.91929], [32.48122, -20.63319], [32.55167, -20.56312], [32.66174, -20.56106], [32.85987, -20.27841], [32.85987, -20.16686], [32.93032, -20.03868], [33.01178, -20.02007], [33.06461, -19.77787], [32.95013, -19.67219], [32.84666, -19.68462], [32.84446, -19.48343], [32.78282, -19.47513], [32.77966, -19.36098], [32.85107, -19.29238], [32.87088, -19.09279], [32.84006, -19.0262], [32.72118, -19.02204], [32.69917, -18.94293], [32.73439, -18.92628], [32.70137, -18.84712], [32.82465, -18.77419], [32.9017, -18.7992], [32.95013, -18.69079], [32.88629, -18.58023], [32.88629, -18.51344], [33.02278, -18.4696], [33.03159, -18.35054], [32.94133, -17.99705], [33.0492, -17.60298], [32.98536, -17.55891], [32.96554, -17.48964], [33.0426, -17.3468], [33.00517, -17.30477], [32.96554, -17.11971], [32.84113, -16.92259], [32.91051, -16.89446], [32.97655, -16.70689], [32.78943, -16.70267], [32.69917, -16.66893], [32.71017, -16.59932], [32.42838, -16.4727], [32.28529, -16.43892], [32.02772, -16.43892], [31.91324, -16.41569], [31.90223, -16.34388], [31.67988, -16.19595], [31.42451, -16.15154], [31.30563, -16.01193], [31.13171, -15.98019], [30.97761, -16.05848], [30.91597, -15.99924], [30.42568, -15.9962], [30.41902, -15.62269]]]]
27763 var borders_default = {
27766 }; // src/country-coder.ts
27768 var borders = borders_default;
27769 var whichPolygonGetter = {};
27770 var featuresByCode = {};
27771 var idFilterRegex = /(?=(?!^(and|the|of|el|la|de)$))(\b(and|the|of|el|la|de)\b)|[-_ .,'()&[\]/]/gi;
27773 function canonicalID(id) {
27776 if (s.charAt(0) === ".") {
27777 return s.toUpperCase();
27779 return s.replace(idFilterRegex, "").toUpperCase();
27783 var levels = ["subterritory", "territory", "subcountryGroup", "country", "sharedLandform", "intermediateRegion", "subregion", "region", "subunion", "union", "unitedNations", "world"];
27784 loadDerivedDataAndCaches(borders);
27786 function loadDerivedDataAndCaches(borders2) {
27787 var identifierProps = ["iso1A2", "iso1A3", "m49", "wikidata", "emojiFlag", "ccTLD", "nameEn"];
27788 var geometryFeatures = [];
27790 for (var i in borders2.features) {
27791 var feature2 = borders2.features[i];
27792 feature2.properties.id = feature2.properties.iso1A2 || feature2.properties.m49 || feature2.properties.wikidata;
27795 loadIsoStatus(feature2);
27796 loadLevel(feature2);
27797 loadGroups(feature2);
27798 loadFlag(feature2);
27799 cacheFeatureByIDs(feature2);
27800 if (feature2.geometry) geometryFeatures.push(feature2);
27803 for (var _i in borders2.features) {
27804 var _feature = borders2.features[_i];
27805 _feature.properties.groups = _feature.properties.groups.map(function (groupID) {
27806 return featuresByCode[groupID].properties.id;
27808 loadMembersForGroupsOf(_feature);
27811 for (var _i2 in borders2.features) {
27812 var _feature2 = borders2.features[_i2];
27813 loadRoadSpeedUnit(_feature2);
27814 loadRoadHeightUnit(_feature2);
27815 loadDriveSide(_feature2);
27816 loadCallingCodes(_feature2);
27817 loadGroupGroups(_feature2);
27820 for (var _i3 in borders2.features) {
27821 var _feature3 = borders2.features[_i3];
27823 _feature3.properties.groups.sort(function (groupID1, groupID2) {
27824 return levels.indexOf(featuresByCode[groupID1].properties.level) - levels.indexOf(featuresByCode[groupID2].properties.level);
27827 if (_feature3.properties.members) _feature3.properties.members.sort(function (id1, id2) {
27828 var diff = levels.indexOf(featuresByCode[id1].properties.level) - levels.indexOf(featuresByCode[id2].properties.level);
27831 return borders2.features.indexOf(featuresByCode[id1]) - borders2.features.indexOf(featuresByCode[id2]);
27838 var geometryOnlyCollection = {
27839 type: "FeatureCollection",
27840 features: geometryFeatures
27842 whichPolygonGetter = whichPolygon_1(geometryOnlyCollection);
27844 function loadGroups(feature2) {
27845 var props = feature2.properties;
27847 if (!props.groups) {
27851 if (feature2.geometry && props.country) {
27852 props.groups.push(props.country);
27855 if (props.m49 !== "001") {
27856 props.groups.push("001");
27860 function loadM49(feature2) {
27861 var props = feature2.properties;
27863 if (!props.m49 && props.iso1N3) {
27864 props.m49 = props.iso1N3;
27868 function loadTLD(feature2) {
27869 var props = feature2.properties;
27870 if (props.level === "unitedNations") return;
27872 if (!props.ccTLD && props.iso1A2) {
27873 props.ccTLD = "." + props.iso1A2.toLowerCase();
27877 function loadIsoStatus(feature2) {
27878 var props = feature2.properties;
27880 if (!props.isoStatus && props.iso1A2) {
27881 props.isoStatus = "official";
27885 function loadLevel(feature2) {
27886 var props = feature2.properties;
27887 if (props.level) return;
27889 if (!props.country) {
27890 props.level = "country";
27891 } else if (!props.iso1A2 || props.isoStatus === "official") {
27892 props.level = "territory";
27894 props.level = "subterritory";
27898 function loadGroupGroups(feature2) {
27899 var props = feature2.properties;
27900 if (feature2.geometry || !props.members) return;
27901 var featureLevelIndex = levels.indexOf(props.level);
27902 var sharedGroups = [];
27904 var _loop = function _loop(_i4) {
27905 var memberID = props.members[_i4];
27906 var member = featuresByCode[memberID];
27907 var memberGroups = member.properties.groups.filter(function (groupID) {
27908 return groupID !== feature2.properties.id && featureLevelIndex < levels.indexOf(featuresByCode[groupID].properties.level);
27912 sharedGroups = memberGroups;
27914 sharedGroups = sharedGroups.filter(function (groupID) {
27915 return memberGroups.indexOf(groupID) !== -1;
27920 for (var _i4 in props.members) {
27924 props.groups = props.groups.concat(sharedGroups.filter(function (groupID) {
27925 return props.groups.indexOf(groupID) === -1;
27928 for (var j in sharedGroups) {
27929 var groupFeature = featuresByCode[sharedGroups[j]];
27931 if (groupFeature.properties.members.indexOf(props.id) === -1) {
27932 groupFeature.properties.members.push(props.id);
27937 function loadRoadSpeedUnit(feature2) {
27938 var props = feature2.properties;
27940 if (feature2.geometry) {
27941 if (!props.roadSpeedUnit) props.roadSpeedUnit = "km/h";
27942 } else if (props.members) {
27943 var vals = Array.from(new Set(props.members.map(function (id) {
27944 var member = featuresByCode[id];
27945 if (member.geometry) return member.properties.roadSpeedUnit || "km/h";
27946 }).filter(Boolean)));
27947 if (vals.length === 1) props.roadSpeedUnit = vals[0];
27951 function loadRoadHeightUnit(feature2) {
27952 var props = feature2.properties;
27954 if (feature2.geometry) {
27955 if (!props.roadHeightUnit) props.roadHeightUnit = "m";
27956 } else if (props.members) {
27957 var vals = Array.from(new Set(props.members.map(function (id) {
27958 var member = featuresByCode[id];
27959 if (member.geometry) return member.properties.roadHeightUnit || "m";
27960 }).filter(Boolean)));
27961 if (vals.length === 1) props.roadHeightUnit = vals[0];
27965 function loadDriveSide(feature2) {
27966 var props = feature2.properties;
27968 if (feature2.geometry) {
27969 if (!props.driveSide) props.driveSide = "right";
27970 } else if (props.members) {
27971 var vals = Array.from(new Set(props.members.map(function (id) {
27972 var member = featuresByCode[id];
27973 if (member.geometry) return member.properties.driveSide || "right";
27974 }).filter(Boolean)));
27975 if (vals.length === 1) props.driveSide = vals[0];
27979 function loadCallingCodes(feature2) {
27980 var props = feature2.properties;
27982 if (!feature2.geometry && props.members) {
27983 props.callingCodes = Array.from(new Set(props.members.reduce(function (array, id) {
27984 var member = featuresByCode[id];
27985 if (member.geometry && member.properties.callingCodes) return array.concat(member.properties.callingCodes);
27991 function loadFlag(feature2) {
27992 if (!feature2.properties.iso1A2) return;
27993 var flag = feature2.properties.iso1A2.replace(/./g, function (_char) {
27994 return String.fromCodePoint(_char.charCodeAt(0) + 127397);
27996 feature2.properties.emojiFlag = flag;
27999 function loadMembersForGroupsOf(feature2) {
28000 for (var j in feature2.properties.groups) {
28001 var groupID = feature2.properties.groups[j];
28002 var groupFeature = featuresByCode[groupID];
28003 if (!groupFeature.properties.members) groupFeature.properties.members = [];
28004 groupFeature.properties.members.push(feature2.properties.id);
28008 function cacheFeatureByIDs(feature2) {
28011 for (var k in identifierProps) {
28012 var prop = identifierProps[k];
28013 var id = feature2.properties[prop];
28014 if (id) ids.push(id);
28017 if (feature2.properties.aliases) {
28018 for (var j in feature2.properties.aliases) {
28019 ids.push(feature2.properties.aliases[j]);
28023 for (var _i5 in ids) {
28024 var _id = canonicalID(ids[_i5]);
28026 featuresByCode[_id] = feature2;
28031 function locArray(loc) {
28032 if (Array.isArray(loc)) {
28034 } else if (loc.coordinates) {
28035 return loc.coordinates;
28038 return loc.geometry.coordinates;
28041 function smallestFeature(loc) {
28042 var query = locArray(loc);
28043 var featureProperties = whichPolygonGetter(query);
28044 if (!featureProperties) return null;
28045 return featuresByCode[featureProperties.id];
28048 function countryFeature(loc) {
28049 var feature2 = smallestFeature(loc);
28050 if (!feature2) return null;
28051 var countryCode = feature2.properties.country || feature2.properties.iso1A2;
28052 return featuresByCode[countryCode] || null;
28055 var defaultOpts = {
28061 function featureForLoc(loc, opts) {
28062 var targetLevel = opts.level || "country";
28063 var maxLevel = opts.maxLevel || "world";
28064 var withProp = opts.withProp;
28065 var targetLevelIndex = levels.indexOf(targetLevel);
28066 if (targetLevelIndex === -1) return null;
28067 var maxLevelIndex = levels.indexOf(maxLevel);
28068 if (maxLevelIndex === -1) return null;
28069 if (maxLevelIndex < targetLevelIndex) return null;
28071 if (targetLevel === "country") {
28072 var fastFeature = countryFeature(loc);
28075 if (!withProp || fastFeature.properties[withProp]) {
28076 return fastFeature;
28081 var features2 = featuresContaining(loc);
28083 for (var i in features2) {
28084 var feature2 = features2[i];
28085 var levelIndex = levels.indexOf(feature2.properties.level);
28087 if (feature2.properties.level === targetLevel || levelIndex > targetLevelIndex && levelIndex <= maxLevelIndex) {
28088 if (!withProp || feature2.properties[withProp]) {
28097 function featureForID(id) {
28100 if (typeof id === "number") {
28101 stringID = id.toString();
28103 if (stringID.length === 1) {
28104 stringID = "00" + stringID;
28105 } else if (stringID.length === 2) {
28106 stringID = "0" + stringID;
28109 stringID = canonicalID(id);
28112 return featuresByCode[stringID] || null;
28115 function smallestFeaturesForBbox(bbox) {
28116 return whichPolygonGetter.bbox(bbox).map(function (props) {
28117 return featuresByCode[props.id];
28121 function smallestOrMatchingFeature(query) {
28122 if (_typeof(query) === "object") {
28123 return smallestFeature(query);
28126 return featureForID(query);
28129 function feature$1(query) {
28130 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
28132 if (_typeof(query) === "object") {
28133 return featureForLoc(query, opts);
28136 return featureForID(query);
28139 function iso1A2Code(query) {
28140 var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : defaultOpts;
28141 opts.withProp = "iso1A2";
28142 var match = feature$1(query, opts);
28143 if (!match) return null;
28144 return match.properties.iso1A2 || null;
28147 function featuresContaining(query, strict) {
28148 var matchingFeatures;
28150 if (Array.isArray(query) && query.length === 4) {
28151 matchingFeatures = smallestFeaturesForBbox(query);
28153 var smallestOrMatching = smallestOrMatchingFeature(query);
28154 matchingFeatures = smallestOrMatching ? [smallestOrMatching] : [];
28157 if (!matchingFeatures.length) return [];
28158 var returnFeatures;
28160 if (!strict || _typeof(query) === "object") {
28161 returnFeatures = matchingFeatures.slice();
28163 returnFeatures = [];
28166 for (var j in matchingFeatures) {
28167 var properties = matchingFeatures[j].properties;
28169 for (var i in properties.groups) {
28170 var groupID = properties.groups[i];
28171 var groupFeature = featuresByCode[groupID];
28173 if (returnFeatures.indexOf(groupFeature) === -1) {
28174 returnFeatures.push(groupFeature);
28179 return returnFeatures;
28182 function featuresIn(id, strict) {
28183 var feature2 = featureForID(id);
28184 if (!feature2) return [];
28185 var features2 = [];
28188 features2.push(feature2);
28191 var properties = feature2.properties;
28193 if (properties.members) {
28194 for (var i in properties.members) {
28195 var memberID = properties.members[i];
28196 features2.push(featuresByCode[memberID]);
28203 function aggregateFeature(id) {
28204 var features2 = featuresIn(id, false);
28205 if (features2.length === 0) return null;
28206 var aggregateCoordinates = [];
28208 for (var i in features2) {
28209 var feature2 = features2[i];
28211 if (feature2.geometry && feature2.geometry.type === "MultiPolygon" && feature2.geometry.coordinates) {
28212 aggregateCoordinates = aggregateCoordinates.concat(feature2.geometry.coordinates);
28218 properties: features2[0].properties,
28220 type: "MultiPolygon",
28221 coordinates: aggregateCoordinates
28226 function roadSpeedUnit(query) {
28227 var feature2 = smallestOrMatchingFeature(query);
28228 return feature2 && feature2.properties.roadSpeedUnit || null;
28231 function roadHeightUnit(query) {
28232 var feature2 = smallestOrMatchingFeature(query);
28233 return feature2 && feature2.properties.roadHeightUnit || null;
28236 var geojsonArea = {};
28240 wgs84$1.RADIUS = 6378137;
28241 wgs84$1.FLATTENING = 1 / 298.257223563;
28242 wgs84$1.POLAR_RADIUS = 6356752.3142;
28244 var wgs84 = wgs84$1;
28245 geojsonArea.geometry = geometry;
28246 geojsonArea.ring = ringArea;
28248 function geometry(_) {
28254 return polygonArea(_.coordinates);
28256 case 'MultiPolygon':
28257 for (i = 0; i < _.coordinates.length; i++) {
28258 area += polygonArea(_.coordinates[i]);
28266 case 'MultiLineString':
28269 case 'GeometryCollection':
28270 for (i = 0; i < _.geometries.length; i++) {
28271 area += geometry(_.geometries[i]);
28278 function polygonArea(coords) {
28281 if (coords && coords.length > 0) {
28282 area += Math.abs(ringArea(coords[0]));
28284 for (var i = 1; i < coords.length; i++) {
28285 area -= Math.abs(ringArea(coords[i]));
28292 * Calculate the approximate area of the polygon were it projected onto
28293 * the earth. Note that this area will be positive if ring is oriented
28294 * clockwise, otherwise it will be negative.
28297 * Robert. G. Chamberlain and William H. Duquette, "Some Algorithms for
28298 * Polygons on a Sphere", JPL Publication 07-03, Jet Propulsion
28299 * Laboratory, Pasadena, CA, June 2007 http://trs-new.jpl.nasa.gov/dspace/handle/2014/40409
28302 * {float} The approximate signed geodesic area of the polygon in square
28307 function ringArea(coords) {
28316 coordsLength = coords.length;
28318 if (coordsLength > 2) {
28319 for (i = 0; i < coordsLength; i++) {
28320 if (i === coordsLength - 2) {
28322 lowerIndex = coordsLength - 2;
28323 middleIndex = coordsLength - 1;
28325 } else if (i === coordsLength - 1) {
28327 lowerIndex = coordsLength - 1;
28333 middleIndex = i + 1;
28334 upperIndex = i + 2;
28337 p1 = coords[lowerIndex];
28338 p2 = coords[middleIndex];
28339 p3 = coords[upperIndex];
28340 area += (rad(p3[0]) - rad(p1[0])) * Math.sin(rad(p2[1]));
28343 area = area * wgs84.RADIUS * wgs84.RADIUS / 2;
28350 return _ * Math.PI / 180;
28353 var inputValidation = {};
28356 var $includes = arrayIncludes.includes;
28357 var addToUnscopables$1 = addToUnscopables$5;
28359 // `Array.prototype.includes` method
28360 // https://tc39.es/ecma262/#sec-array.prototype.includes
28361 $$g({ target: 'Array', proto: true }, {
28362 includes: function includes(el /* , fromIndex = 0 */) {
28363 return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
28367 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
28368 addToUnscopables$1('includes');
28370 var validateCenter$1 = {};
28372 validateCenter$1.validateCenter = function validateCenter(center) {
28373 var validCenterLengths = [2, 3];
28375 if (!Array.isArray(center) || !validCenterLengths.includes(center.length)) {
28376 throw new Error("ERROR! Center has to be an array of length two or three");
28379 var _center = _slicedToArray(center, 2),
28383 if (typeof lng !== "number" || typeof lat !== "number") {
28384 throw new Error("ERROR! Longitude and Latitude has to be numbers but where ".concat(_typeof(lng), " and ").concat(_typeof(lat)));
28387 if (lng > 180 || lng < -180) {
28388 throw new Error("ERROR! Longitude has to be between -180 and 180 but was ".concat(lng));
28391 if (lat > 90 || lat < -90) {
28392 throw new Error("ERROR! Latitude has to be between -90 and 90 but was ".concat(lat));
28396 var validateRadius$1 = {};
28398 validateRadius$1.validateRadius = function validateRadius(radius) {
28399 if (typeof radius !== "number") {
28400 throw new Error("ERROR! Radius has to be a positive number but was: ".concat(_typeof(radius)));
28404 throw new Error("ERROR! Radius has to be a positive number but was: ".concat(radius));
28408 var validateNumberOfEdges$1 = {};
28410 validateNumberOfEdges$1.validateNumberOfEdges = function validateNumberOfEdges(numberOfEdges) {
28411 if (typeof numberOfEdges !== "number") {
28412 var ARGUMENT_TYPE = Array.isArray(numberOfEdges) ? "array" : _typeof(numberOfEdges);
28413 throw new Error("ERROR! Number of edges has to be a number but was: ".concat(ARGUMENT_TYPE));
28416 if (numberOfEdges < 3) {
28417 throw new Error("ERROR! Number of edges has to be at least 3 but was: ".concat(numberOfEdges));
28421 var validateEarthRadius$1 = {};
28423 validateEarthRadius$1.validateEarthRadius = function validateEarthRadius(earthRadius) {
28424 if (typeof earthRadius !== "number") {
28425 var ARGUMENT_TYPE = Array.isArray(earthRadius) ? "array" : _typeof(earthRadius);
28426 throw new Error("ERROR! Earth radius has to be a number but was: ".concat(ARGUMENT_TYPE));
28429 if (earthRadius <= 0) {
28430 throw new Error("ERROR! Earth radius has to be a positive number but was: ".concat(earthRadius));
28434 var validateBearing$1 = {};
28436 validateBearing$1.validateBearing = function validateBearing(bearing) {
28437 if (typeof bearing !== "number") {
28438 var ARGUMENT_TYPE = Array.isArray(bearing) ? "array" : _typeof(bearing);
28439 throw new Error("ERROR! Bearing has to be a number but was: ".concat(ARGUMENT_TYPE));
28443 var validateCenter = validateCenter$1.validateCenter;
28444 var validateRadius = validateRadius$1.validateRadius;
28445 var validateNumberOfEdges = validateNumberOfEdges$1.validateNumberOfEdges;
28446 var validateEarthRadius = validateEarthRadius$1.validateEarthRadius;
28447 var validateBearing = validateBearing$1.validateBearing;
28449 function validateInput$1(_ref) {
28450 var center = _ref.center,
28451 radius = _ref.radius,
28452 numberOfEdges = _ref.numberOfEdges,
28453 earthRadius = _ref.earthRadius,
28454 bearing = _ref.bearing;
28455 validateCenter(center);
28456 validateRadius(radius);
28457 validateNumberOfEdges(numberOfEdges);
28458 validateEarthRadius(earthRadius);
28459 validateBearing(bearing);
28462 inputValidation.validateCenter = validateCenter;
28463 inputValidation.validateRadius = validateRadius;
28464 inputValidation.validateNumberOfEdges = validateNumberOfEdges;
28465 inputValidation.validateEarthRadius = validateEarthRadius;
28466 inputValidation.validateBearing = validateBearing;
28467 inputValidation.validateInput = validateInput$1;
28469 var validateInput = inputValidation.validateInput;
28470 var defaultEarthRadius = 6378137; // equatorial Earth radius
28472 function toRadians(angleInDegrees) {
28473 return angleInDegrees * Math.PI / 180;
28476 function toDegrees(angleInRadians) {
28477 return angleInRadians * 180 / Math.PI;
28480 function offset(c1, distance, earthRadius, bearing) {
28481 var lat1 = toRadians(c1[1]);
28482 var lon1 = toRadians(c1[0]);
28483 var dByR = distance / earthRadius;
28484 var lat = Math.asin(Math.sin(lat1) * Math.cos(dByR) + Math.cos(lat1) * Math.sin(dByR) * Math.cos(bearing));
28485 var lon = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(dByR) * Math.cos(lat1), Math.cos(dByR) - Math.sin(lat1) * Math.sin(lat));
28486 return [toDegrees(lon), toDegrees(lat)];
28489 var circleToPolygon = function circleToPolygon(center, radius, options) {
28490 var n = getNumberOfEdges(options);
28491 var earthRadius = getEarthRadius(options);
28492 var bearing = getBearing(options);
28493 var direction = getDirection(options); // validateInput() throws error on invalid input and do nothing on valid input
28499 earthRadius: earthRadius,
28502 var start = toRadians(bearing);
28503 var coordinates = [];
28505 for (var i = 0; i < n; ++i) {
28506 coordinates.push(offset(center, radius, earthRadius, start + direction * 2 * Math.PI * -i / n));
28509 coordinates.push(coordinates[0]);
28512 coordinates: [coordinates]
28516 function getNumberOfEdges(options) {
28517 if (isUndefinedOrNull(options)) {
28519 } else if (isObjectNotArray(options)) {
28520 var numberOfEdges = options.numberOfEdges;
28521 return numberOfEdges === undefined ? 32 : numberOfEdges;
28527 function getEarthRadius(options) {
28528 if (isUndefinedOrNull(options)) {
28529 return defaultEarthRadius;
28530 } else if (isObjectNotArray(options)) {
28531 var earthRadius = options.earthRadius;
28532 return earthRadius === undefined ? defaultEarthRadius : earthRadius;
28535 return defaultEarthRadius;
28538 function getDirection(options) {
28539 if (isObjectNotArray(options) && options.rightHandRule) {
28546 function getBearing(options) {
28547 if (isUndefinedOrNull(options)) {
28549 } else if (isObjectNotArray(options)) {
28550 var bearing = options.bearing;
28551 return bearing === undefined ? 0 : bearing;
28557 function isObjectNotArray(argument) {
28558 return argument !== null && _typeof(argument) === "object" && !Array.isArray(argument);
28561 function isUndefinedOrNull(argument) {
28562 return argument === null || argument === undefined;
28567 // `Number.EPSILON` constant
28568 // https://tc39.es/ecma262/#sec-number.epsilon
28569 $$f({ target: 'Number', stat: true }, {
28570 EPSILON: Math.pow(2, -52)
28573 var requireObjectCoercible$4 = requireObjectCoercible$e;
28577 // `CreateHTML` abstract operation
28578 // https://tc39.es/ecma262/#sec-createhtml
28579 var createHtml = function (string, tag, attribute, value) {
28580 var S = String(requireObjectCoercible$4(string));
28581 var p1 = '<' + tag;
28582 if (attribute !== '') p1 += ' ' + attribute + '="' + String(value).replace(quot, '"') + '"';
28583 return p1 + '>' + S + '</' + tag + '>';
28586 var fails$6 = fails$N;
28588 // check the existence of a method, lowercase
28589 // of a tag and escaping quotes in arguments
28590 var stringHtmlForced = function (METHOD_NAME) {
28591 return fails$6(function () {
28592 var test = ''[METHOD_NAME]('"');
28593 return test !== test.toLowerCase() || test.split('"').length > 3;
28598 var createHTML = createHtml;
28599 var forcedStringHTMLMethod = stringHtmlForced;
28601 // `String.prototype.link` method
28602 // https://tc39.es/ecma262/#sec-string.prototype.link
28603 $$e({ target: 'String', proto: true, forced: forcedStringHTMLMethod('link') }, {
28604 link: function link(url) {
28605 return createHTML(this, 'a', 'href', url);
28611 * Fast Splay tree for Node and browser
28613 * @author Alexander Milevski <info@w8r.name>
28620 function Node(key, data) {
28630 /* follows "An implementation of top-down splaying"
28631 * by D. Sleator <sleator@cs.cmu.edu> March 1992
28635 function DEFAULT_COMPARE(a, b) {
28636 return a > b ? 1 : a < b ? -1 : 0;
28639 * Simple top down splay, not requiring i to be in the tree t.
28643 function splay(i, t, comparator) {
28644 var N = new Node(null, null);
28649 var cmp = comparator(i, t.key); //if (i < t.key) {
28652 if (t.left === null) break; //if (i < t.left.key) {
28654 if (comparator(i, t.left.key) < 0) {
28661 if (t.left === null) break;
28668 t = t.left; //} else if (i > t.key) {
28669 } else if (cmp > 0) {
28670 if (t.right === null) break; //if (i > t.right.key) {
28672 if (comparator(i, t.right.key) > 0) {
28679 if (t.right === null) break;
28699 function insert(i, data, t, comparator) {
28700 var node = new Node(i, data);
28703 node.left = node.right = null;
28707 t = splay(i, t, comparator);
28708 var cmp = comparator(i, t.key);
28711 node.left = t.left;
28714 } else if (cmp >= 0) {
28715 node.right = t.right;
28723 function split(key, v, comparator) {
28728 v = splay(key, v, comparator);
28729 var cmp = comparator(v.key, key);
28734 } else if (cmp < 0) {
28751 function merge$3(left, right, comparator) {
28752 if (right === null) return left;
28753 if (left === null) return right;
28754 right = splay(left.key, right, comparator);
28759 * Prints level of the tree
28763 function printRow(root, prefix, isTail, out, printNode) {
28765 out("" + prefix + (isTail ? '└── ' : '├── ') + printNode(root) + "\n");
28766 var indent = prefix + (isTail ? ' ' : '│ ');
28767 if (root.left) printRow(root.left, indent, false, out, printNode);
28768 if (root.right) printRow(root.right, indent, true, out, printNode);
28775 function Tree(comparator) {
28776 if (comparator === void 0) {
28777 comparator = DEFAULT_COMPARE;
28782 this._comparator = comparator;
28785 * Inserts a key, allows duplicates
28789 Tree.prototype.insert = function (key, data) {
28791 return this._root = insert(key, data, this._root, this._comparator);
28794 * Adds a key, if it is not present in the tree
28798 Tree.prototype.add = function (key, data) {
28799 var node = new Node(key, data);
28801 if (this._root === null) {
28802 node.left = node.right = null;
28807 var comparator = this._comparator;
28808 var t = splay(key, this._root, comparator);
28809 var cmp = comparator(key, t.key);
28810 if (cmp === 0) this._root = t;else {
28812 node.left = t.left;
28815 } else if (cmp > 0) {
28816 node.right = t.right;
28828 * @return {Node|null}
28832 Tree.prototype.remove = function (key) {
28833 this._root = this._remove(key, this._root, this._comparator);
28836 * Deletes i from the tree if it's there
28840 Tree.prototype._remove = function (i, t, comparator) {
28842 if (t === null) return null;
28843 t = splay(i, t, comparator);
28844 var cmp = comparator(i, t.key);
28848 if (t.left === null) {
28851 x = splay(i, t.left, comparator);
28860 /* It wasn't there */
28863 * Removes and returns the node with smallest key
28867 Tree.prototype.pop = function () {
28868 var node = this._root;
28871 while (node.left) {
28875 this._root = splay(node.key, this._root, this._comparator);
28876 this._root = this._remove(node.key, this._root, this._comparator);
28886 * Find without splaying
28890 Tree.prototype.findStatic = function (key) {
28891 var current = this._root;
28892 var compare = this._comparator;
28895 var cmp = compare(key, current.key);
28896 if (cmp === 0) return current;else if (cmp < 0) current = current.left;else current = current.right;
28902 Tree.prototype.find = function (key) {
28904 this._root = splay(key, this._root, this._comparator);
28905 if (this._comparator(key, this._root.key) !== 0) return null;
28911 Tree.prototype.contains = function (key) {
28912 var current = this._root;
28913 var compare = this._comparator;
28916 var cmp = compare(key, current.key);
28917 if (cmp === 0) return true;else if (cmp < 0) current = current.left;else current = current.right;
28923 Tree.prototype.forEach = function (visitor, ctx) {
28924 var current = this._root;
28926 /* Initialize stack s */
28931 if (current !== null) {
28933 current = current.left;
28935 if (Q.length !== 0) {
28937 visitor.call(ctx, current);
28938 current = current.right;
28939 } else done = true;
28946 * Walk key range from `low` to `high`. Stops if `fn` returns a value.
28950 Tree.prototype.range = function (low, high, fn, ctx) {
28952 var compare = this._comparator;
28953 var node = this._root;
28956 while (Q.length !== 0 || node) {
28962 cmp = compare(node.key, high);
28966 } else if (compare(node.key, low) >= 0) {
28967 if (fn.call(ctx, node)) return this; // stop if smth is returned
28977 * Returns array of keys
28981 Tree.prototype.keys = function () {
28983 this.forEach(function (_a) {
28985 return keys.push(key);
28990 * Returns array of all the data in the nodes
28994 Tree.prototype.values = function () {
28996 this.forEach(function (_a) {
28997 var data = _a.data;
28998 return values.push(data);
29003 Tree.prototype.min = function () {
29004 if (this._root) return this.minNode(this._root).key;
29008 Tree.prototype.max = function () {
29009 if (this._root) return this.maxNode(this._root).key;
29013 Tree.prototype.minNode = function (t) {
29014 if (t === void 0) {
29018 if (t) while (t.left) {
29024 Tree.prototype.maxNode = function (t) {
29025 if (t === void 0) {
29029 if (t) while (t.right) {
29035 * Returns node at given index
29039 Tree.prototype.at = function (index) {
29040 var current = this._root;
29048 current = current.left;
29050 if (Q.length > 0) {
29052 if (i === index) return current;
29054 current = current.right;
29055 } else done = true;
29062 Tree.prototype.next = function (d) {
29063 var root = this._root;
29064 var successor = null;
29067 successor = d.right;
29069 while (successor.left) {
29070 successor = successor.left;
29076 var comparator = this._comparator;
29079 var cmp = comparator(d.key, root.key);
29080 if (cmp === 0) break;else if (cmp < 0) {
29083 } else root = root.right;
29089 Tree.prototype.prev = function (d) {
29090 var root = this._root;
29091 var predecessor = null;
29093 if (d.left !== null) {
29094 predecessor = d.left;
29096 while (predecessor.right) {
29097 predecessor = predecessor.right;
29100 return predecessor;
29103 var comparator = this._comparator;
29106 var cmp = comparator(d.key, root.key);
29107 if (cmp === 0) break;else if (cmp < 0) root = root.left;else {
29108 predecessor = root;
29113 return predecessor;
29116 Tree.prototype.clear = function () {
29122 Tree.prototype.toList = function () {
29123 return toList(this._root);
29126 * Bulk-load items. Both array have to be same size
29130 Tree.prototype.load = function (keys, values, presort) {
29131 if (values === void 0) {
29135 if (presort === void 0) {
29139 var size = keys.length;
29140 var comparator = this._comparator; // sort if needed
29142 if (presort) sort(keys, values, 0, size - 1, comparator);
29144 if (this._root === null) {
29146 this._root = loadRecursive(keys, values, 0, size);
29149 // that re-builds the whole tree from two in-order traversals
29150 var mergedList = mergeLists(this.toList(), createList(keys, values), comparator);
29151 size = this._size + size;
29152 this._root = sortedListToBST({
29160 Tree.prototype.isEmpty = function () {
29161 return this._root === null;
29164 Object.defineProperty(Tree.prototype, "size", {
29165 get: function get() {
29171 Object.defineProperty(Tree.prototype, "root", {
29172 get: function get() {
29179 Tree.prototype.toString = function (printNode) {
29180 if (printNode === void 0) {
29181 printNode = function printNode(n) {
29182 return String(n.key);
29187 printRow(this._root, '', true, function (v) {
29188 return out.push(v);
29190 return out.join('');
29193 Tree.prototype.update = function (key, newKey, newData) {
29194 var comparator = this._comparator;
29196 var _a = split(key, this._root, comparator),
29200 if (comparator(key, newKey) < 0) {
29201 right = insert(newKey, newData, right, comparator);
29203 left = insert(newKey, newData, left, comparator);
29206 this._root = merge$3(left, right, comparator);
29209 Tree.prototype.split = function (key) {
29210 return split(key, this._root, this._comparator);
29216 function loadRecursive(keys, values, start, end) {
29217 var size = end - start;
29220 var middle = start + Math.floor(size / 2);
29221 var key = keys[middle];
29222 var data = values[middle];
29223 var node = new Node(key, data);
29224 node.left = loadRecursive(keys, values, start, middle);
29225 node.right = loadRecursive(keys, values, middle + 1, end);
29232 function createList(keys, values) {
29233 var head = new Node(null, null);
29236 for (var i = 0; i < keys.length; i++) {
29237 p = p.next = new Node(keys[i], values[i]);
29244 function toList(root) {
29245 var current = root;
29248 var head = new Node(null, null);
29254 current = current.left;
29256 if (Q.length > 0) {
29257 current = p = p.next = Q.pop();
29258 current = current.right;
29259 } else done = true;
29263 p.next = null; // that'll work even if the tree was empty
29268 function sortedListToBST(list, start, end) {
29269 var size = end - start;
29272 var middle = start + Math.floor(size / 2);
29273 var left = sortedListToBST(list, start, middle);
29274 var root = list.head;
29276 list.head = list.head.next;
29277 root.right = sortedListToBST(list, middle + 1, end);
29284 function mergeLists(l1, l2, compare) {
29285 var head = new Node(null, null); // dummy
29291 while (p1 !== null && p2 !== null) {
29292 if (compare(p1.key, p2.key) < 0) {
29305 } else if (p2 !== null) {
29312 function sort(keys, values, left, right, compare) {
29313 if (left >= right) return;
29314 var pivot = keys[left + right >> 1];
29321 } while (compare(keys[i], pivot) < 0);
29325 } while (compare(keys[j], pivot) > 0);
29332 values[i] = values[j];
29336 sort(keys, values, left, j, compare);
29337 sort(keys, values, j + 1, right, compare);
29340 function _classCallCheck(instance, Constructor) {
29341 if (!(instance instanceof Constructor)) {
29342 throw new TypeError("Cannot call a class as a function");
29346 function _defineProperties(target, props) {
29347 for (var i = 0; i < props.length; i++) {
29348 var descriptor = props[i];
29349 descriptor.enumerable = descriptor.enumerable || false;
29350 descriptor.configurable = true;
29351 if ("value" in descriptor) descriptor.writable = true;
29352 Object.defineProperty(target, descriptor.key, descriptor);
29356 function _createClass(Constructor, protoProps, staticProps) {
29357 if (protoProps) _defineProperties(Constructor.prototype, protoProps);
29358 if (staticProps) _defineProperties(Constructor, staticProps);
29359 return Constructor;
29362 * A bounding box has the format:
29364 * { ll: { x: xmin, y: ymin }, ur: { x: xmax, y: ymax } }
29369 var isInBbox = function isInBbox(bbox, point) {
29370 return bbox.ll.x <= point.x && point.x <= bbox.ur.x && bbox.ll.y <= point.y && point.y <= bbox.ur.y;
29372 /* Returns either null, or a bbox (aka an ordered pair of points)
29373 * If there is only one point of overlap, a bbox with identical points
29374 * will be returned */
29377 var getBboxOverlap = function getBboxOverlap(b1, b2) {
29378 // check if the bboxes overlap at all
29379 if (b2.ur.x < b1.ll.x || b1.ur.x < b2.ll.x || b2.ur.y < b1.ll.y || b1.ur.y < b2.ll.y) return null; // find the middle two X values
29381 var lowerX = b1.ll.x < b2.ll.x ? b2.ll.x : b1.ll.x;
29382 var upperX = b1.ur.x < b2.ur.x ? b1.ur.x : b2.ur.x; // find the middle two Y values
29384 var lowerY = b1.ll.y < b2.ll.y ? b2.ll.y : b1.ll.y;
29385 var upperY = b1.ur.y < b2.ur.y ? b1.ur.y : b2.ur.y; // put those middle values together to get the overlap
29398 /* Javascript doesn't do integer math. Everything is
29399 * floating point with percision Number.EPSILON.
29401 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/EPSILON
29405 var epsilon = Number.EPSILON; // IE Polyfill
29407 if (epsilon === undefined) epsilon = Math.pow(2, -52);
29408 var EPSILON_SQ = epsilon * epsilon;
29409 /* FLP comparator */
29411 var cmp = function cmp(a, b) {
29412 // check if they're both 0
29413 if (-epsilon < a && a < epsilon) {
29414 if (-epsilon < b && b < epsilon) {
29417 } // check if they're flp equal
29422 if (ab * ab < EPSILON_SQ * a * b) {
29424 } // normal comparison
29427 return a < b ? -1 : 1;
29430 * This class rounds incoming values sufficiently so that
29431 * floating points problems are, for the most part, avoided.
29433 * Incoming points are have their x & y values tested against
29434 * all previously seen x & y values. If either is 'too close'
29435 * to a previously seen value, it's value is 'snapped' to the
29436 * previously seen value.
29438 * All points should be rounded by this class before being
29439 * stored in any data structures in the rest of this algorithm.
29443 var PtRounder = /*#__PURE__*/function () {
29444 function PtRounder() {
29445 _classCallCheck(this, PtRounder);
29450 _createClass(PtRounder, [{
29452 value: function reset() {
29453 this.xRounder = new CoordRounder();
29454 this.yRounder = new CoordRounder();
29458 value: function round(x, y) {
29460 x: this.xRounder.round(x),
29461 y: this.yRounder.round(y)
29469 var CoordRounder = /*#__PURE__*/function () {
29470 function CoordRounder() {
29471 _classCallCheck(this, CoordRounder);
29473 this.tree = new Tree(); // preseed with 0 so we don't end up with values < Number.EPSILON
29476 } // Note: this can rounds input values backwards or forwards.
29477 // You might ask, why not restrict this to just rounding
29478 // forwards? Wouldn't that allow left endpoints to always
29479 // remain left endpoints during splitting (never change to
29480 // right). No - it wouldn't, because we snap intersections
29481 // to endpoints (to establish independence from the segment
29482 // angle for t-intersections).
29485 _createClass(CoordRounder, [{
29487 value: function round(coord) {
29488 var node = this.tree.add(coord);
29489 var prevNode = this.tree.prev(node);
29491 if (prevNode !== null && cmp(node.key, prevNode.key) === 0) {
29492 this.tree.remove(coord);
29493 return prevNode.key;
29496 var nextNode = this.tree.next(node);
29498 if (nextNode !== null && cmp(node.key, nextNode.key) === 0) {
29499 this.tree.remove(coord);
29500 return nextNode.key;
29507 return CoordRounder;
29508 }(); // singleton available by import
29511 var rounder = new PtRounder();
29512 /* Cross Product of two vectors with first point at origin */
29514 var crossProduct = function crossProduct(a, b) {
29515 return a.x * b.y - a.y * b.x;
29517 /* Dot Product of two vectors with first point at origin */
29520 var dotProduct = function dotProduct(a, b) {
29521 return a.x * b.x + a.y * b.y;
29523 /* Comparator for two vectors with same starting point */
29526 var compareVectorAngles = function compareVectorAngles(basePt, endPt1, endPt2) {
29528 x: endPt1.x - basePt.x,
29529 y: endPt1.y - basePt.y
29532 x: endPt2.x - basePt.x,
29533 y: endPt2.y - basePt.y
29535 var kross = crossProduct(v1, v2);
29536 return cmp(kross, 0);
29539 var length = function length(v) {
29540 return Math.sqrt(dotProduct(v, v));
29542 /* Get the sine of the angle from pShared -> pAngle to pShaed -> pBase */
29545 var sineOfAngle = function sineOfAngle(pShared, pBase, pAngle) {
29547 x: pBase.x - pShared.x,
29548 y: pBase.y - pShared.y
29551 x: pAngle.x - pShared.x,
29552 y: pAngle.y - pShared.y
29554 return crossProduct(vAngle, vBase) / length(vAngle) / length(vBase);
29556 /* Get the cosine of the angle from pShared -> pAngle to pShaed -> pBase */
29559 var cosineOfAngle = function cosineOfAngle(pShared, pBase, pAngle) {
29561 x: pBase.x - pShared.x,
29562 y: pBase.y - pShared.y
29565 x: pAngle.x - pShared.x,
29566 y: pAngle.y - pShared.y
29568 return dotProduct(vAngle, vBase) / length(vAngle) / length(vBase);
29570 /* Get the x coordinate where the given line (defined by a point and vector)
29571 * crosses the horizontal line with the given y coordiante.
29572 * In the case of parrallel lines (including overlapping ones) returns null. */
29575 var horizontalIntersection = function horizontalIntersection(pt, v, y) {
29576 if (v.y === 0) return null;
29578 x: pt.x + v.x / v.y * (y - pt.y),
29582 /* Get the y coordinate where the given line (defined by a point and vector)
29583 * crosses the vertical line with the given x coordiante.
29584 * In the case of parrallel lines (including overlapping ones) returns null. */
29587 var verticalIntersection = function verticalIntersection(pt, v, x) {
29588 if (v.x === 0) return null;
29591 y: pt.y + v.y / v.x * (x - pt.x)
29594 /* Get the intersection of two lines, each defined by a base point and a vector.
29595 * In the case of parrallel lines (including overlapping ones) returns null. */
29598 var intersection = function intersection(pt1, v1, pt2, v2) {
29599 // take some shortcuts for vertical and horizontal lines
29600 // this also ensures we don't calculate an intersection and then discover
29601 // it's actually outside the bounding box of the line
29602 if (v1.x === 0) return verticalIntersection(pt2, v2, pt1.x);
29603 if (v2.x === 0) return verticalIntersection(pt1, v1, pt2.x);
29604 if (v1.y === 0) return horizontalIntersection(pt2, v2, pt1.y);
29605 if (v2.y === 0) return horizontalIntersection(pt1, v1, pt2.y); // General case for non-overlapping segments.
29606 // This algorithm is based on Schneider and Eberly.
29607 // http://www.cimec.org.ar/~ncalvo/Schneider_Eberly.pdf - pg 244
29609 var kross = crossProduct(v1, v2);
29610 if (kross == 0) return null;
29615 var d1 = crossProduct(ve, v1) / kross;
29616 var d2 = crossProduct(ve, v2) / kross; // take the average of the two calculations to minimize rounding error
29618 var x1 = pt1.x + d2 * v1.x,
29619 x2 = pt2.x + d1 * v2.x;
29620 var y1 = pt1.y + d2 * v1.y,
29621 y2 = pt2.y + d1 * v2.y;
29622 var x = (x1 + x2) / 2;
29623 var y = (y1 + y2) / 2;
29630 var SweepEvent = /*#__PURE__*/function () {
29631 _createClass(SweepEvent, null, [{
29633 // for ordering sweep events in the sweep event queue
29634 value: function compare(a, b) {
29635 // favor event with a point that the sweep line hits first
29636 var ptCmp = SweepEvent.comparePoints(a.point, b.point);
29637 if (ptCmp !== 0) return ptCmp; // the points are the same, so link them if needed
29639 if (a.point !== b.point) a.link(b); // favor right events over left
29641 if (a.isLeft !== b.isLeft) return a.isLeft ? 1 : -1; // we have two matching left or right endpoints
29642 // ordering of this case is the same as for their segments
29644 return Segment.compare(a.segment, b.segment);
29645 } // for ordering points in sweep line order
29648 key: "comparePoints",
29649 value: function comparePoints(aPt, bPt) {
29650 if (aPt.x < bPt.x) return -1;
29651 if (aPt.x > bPt.x) return 1;
29652 if (aPt.y < bPt.y) return -1;
29653 if (aPt.y > bPt.y) return 1;
29655 } // Warning: 'point' input will be modified and re-used (for performance)
29659 function SweepEvent(point, isLeft) {
29660 _classCallCheck(this, SweepEvent);
29662 if (point.events === undefined) point.events = [this];else point.events.push(this);
29663 this.point = point;
29664 this.isLeft = isLeft; // this.segment, this.otherSE set by factory
29667 _createClass(SweepEvent, [{
29669 value: function link(other) {
29670 if (other.point === this.point) {
29671 throw new Error('Tried to link already linked events');
29674 var otherEvents = other.point.events;
29676 for (var i = 0, iMax = otherEvents.length; i < iMax; i++) {
29677 var evt = otherEvents[i];
29678 this.point.events.push(evt);
29679 evt.point = this.point;
29682 this.checkForConsuming();
29684 /* Do a pass over our linked events and check to see if any pair
29685 * of segments match, and should be consumed. */
29688 key: "checkForConsuming",
29689 value: function checkForConsuming() {
29690 // FIXME: The loops in this method run O(n^2) => no good.
29691 // Maintain little ordered sweep event trees?
29692 // Can we maintaining an ordering that avoids the need
29693 // for the re-sorting with getLeftmostComparator in geom-out?
29694 // Compare each pair of events to see if other events also match
29695 var numEvents = this.point.events.length;
29697 for (var i = 0; i < numEvents; i++) {
29698 var evt1 = this.point.events[i];
29699 if (evt1.segment.consumedBy !== undefined) continue;
29701 for (var j = i + 1; j < numEvents; j++) {
29702 var evt2 = this.point.events[j];
29703 if (evt2.consumedBy !== undefined) continue;
29704 if (evt1.otherSE.point.events !== evt2.otherSE.point.events) continue;
29705 evt1.segment.consume(evt2.segment);
29710 key: "getAvailableLinkedEvents",
29711 value: function getAvailableLinkedEvents() {
29712 // point.events is always of length 2 or greater
29715 for (var i = 0, iMax = this.point.events.length; i < iMax; i++) {
29716 var evt = this.point.events[i];
29718 if (evt !== this && !evt.segment.ringOut && evt.segment.isInResult()) {
29726 * Returns a comparator function for sorting linked events that will
29727 * favor the event that will give us the smallest left-side angle.
29728 * All ring construction starts as low as possible heading to the right,
29729 * so by always turning left as sharp as possible we'll get polygons
29730 * without uncessary loops & holes.
29732 * The comparator function has a compute cache such that it avoids
29733 * re-computing already-computed values.
29737 key: "getLeftmostComparator",
29738 value: function getLeftmostComparator(baseEvent) {
29741 var cache = new Map();
29743 var fillCache = function fillCache(linkedEvent) {
29744 var nextEvent = linkedEvent.otherSE;
29745 cache.set(linkedEvent, {
29746 sine: sineOfAngle(_this.point, baseEvent.point, nextEvent.point),
29747 cosine: cosineOfAngle(_this.point, baseEvent.point, nextEvent.point)
29751 return function (a, b) {
29752 if (!cache.has(a)) fillCache(a);
29753 if (!cache.has(b)) fillCache(b);
29755 var _cache$get = cache.get(a),
29756 asine = _cache$get.sine,
29757 acosine = _cache$get.cosine;
29759 var _cache$get2 = cache.get(b),
29760 bsine = _cache$get2.sine,
29761 bcosine = _cache$get2.cosine; // both on or above x-axis
29764 if (asine >= 0 && bsine >= 0) {
29765 if (acosine < bcosine) return 1;
29766 if (acosine > bcosine) return -1;
29768 } // both below x-axis
29771 if (asine < 0 && bsine < 0) {
29772 if (acosine < bcosine) return -1;
29773 if (acosine > bcosine) return 1;
29775 } // one above x-axis, one below
29778 if (bsine < asine) return -1;
29779 if (bsine > asine) return 1;
29786 }(); // segments and sweep events when all else is identical
29791 var Segment = /*#__PURE__*/function () {
29792 _createClass(Segment, null, [{
29795 /* This compare() function is for ordering segments in the sweep
29796 * line tree, and does so according to the following criteria:
29798 * Consider the vertical line that lies an infinestimal step to the
29799 * right of the right-more of the two left endpoints of the input
29800 * segments. Imagine slowly moving a point up from negative infinity
29801 * in the increasing y direction. Which of the two segments will that
29802 * point intersect first? That segment comes 'before' the other one.
29804 * If neither segment would be intersected by such a line, (if one
29805 * or more of the segments are vertical) then the line to be considered
29806 * is directly on the right-more of the two left inputs.
29808 value: function compare(a, b) {
29809 var alx = a.leftSE.point.x;
29810 var blx = b.leftSE.point.x;
29811 var arx = a.rightSE.point.x;
29812 var brx = b.rightSE.point.x; // check if they're even in the same vertical plane
29814 if (brx < alx) return 1;
29815 if (arx < blx) return -1;
29816 var aly = a.leftSE.point.y;
29817 var bly = b.leftSE.point.y;
29818 var ary = a.rightSE.point.y;
29819 var bry = b.rightSE.point.y; // is left endpoint of segment B the right-more?
29822 // are the two segments in the same horizontal plane?
29823 if (bly < aly && bly < ary) return 1;
29824 if (bly > aly && bly > ary) return -1; // is the B left endpoint colinear to segment A?
29826 var aCmpBLeft = a.comparePoint(b.leftSE.point);
29827 if (aCmpBLeft < 0) return 1;
29828 if (aCmpBLeft > 0) return -1; // is the A right endpoint colinear to segment B ?
29830 var bCmpARight = b.comparePoint(a.rightSE.point);
29831 if (bCmpARight !== 0) return bCmpARight; // colinear segments, consider the one with left-more
29832 // left endpoint to be first (arbitrary?)
29835 } // is left endpoint of segment A the right-more?
29839 if (aly < bly && aly < bry) return -1;
29840 if (aly > bly && aly > bry) return 1; // is the A left endpoint colinear to segment B?
29842 var bCmpALeft = b.comparePoint(a.leftSE.point);
29843 if (bCmpALeft !== 0) return bCmpALeft; // is the B right endpoint colinear to segment A?
29845 var aCmpBRight = a.comparePoint(b.rightSE.point);
29846 if (aCmpBRight < 0) return 1;
29847 if (aCmpBRight > 0) return -1; // colinear segments, consider the one with left-more
29848 // left endpoint to be first (arbitrary?)
29851 } // if we get here, the two left endpoints are in the same
29852 // vertical plane, ie alx === blx
29853 // consider the lower left-endpoint to come first
29856 if (aly < bly) return -1;
29857 if (aly > bly) return 1; // left endpoints are identical
29858 // check for colinearity by using the left-more right endpoint
29859 // is the A right endpoint more left-more?
29862 var _bCmpARight = b.comparePoint(a.rightSE.point);
29864 if (_bCmpARight !== 0) return _bCmpARight;
29865 } // is the B right endpoint more left-more?
29869 var _aCmpBRight = a.comparePoint(b.rightSE.point);
29871 if (_aCmpBRight < 0) return 1;
29872 if (_aCmpBRight > 0) return -1;
29876 // are these two [almost] vertical segments with opposite orientation?
29877 // if so, the one with the lower right endpoint comes first
29878 var ay = ary - aly;
29879 var ax = arx - alx;
29880 var by = bry - bly;
29881 var bx = brx - blx;
29882 if (ay > ax && by < bx) return 1;
29883 if (ay < ax && by > bx) return -1;
29884 } // we have colinear segments with matching orientation
29885 // consider the one with more left-more right endpoint to be first
29888 if (arx > brx) return 1;
29889 if (arx < brx) return -1; // if we get here, two two right endpoints are in the same
29890 // vertical plane, ie arx === brx
29891 // consider the lower right-endpoint to come first
29893 if (ary < bry) return -1;
29894 if (ary > bry) return 1; // right endpoints identical as well, so the segments are idential
29895 // fall back on creation order as consistent tie-breaker
29897 if (a.id < b.id) return -1;
29898 if (a.id > b.id) return 1; // identical segment, ie a === b
29902 /* Warning: a reference to ringWindings input will be stored,
29903 * and possibly will be later modified */
29907 function Segment(leftSE, rightSE, rings, windings) {
29908 _classCallCheck(this, Segment);
29910 this.id = ++segmentId;
29911 this.leftSE = leftSE;
29912 leftSE.segment = this;
29913 leftSE.otherSE = rightSE;
29914 this.rightSE = rightSE;
29915 rightSE.segment = this;
29916 rightSE.otherSE = leftSE;
29917 this.rings = rings;
29918 this.windings = windings; // left unset for performance, set later in algorithm
29919 // this.ringOut, this.consumedBy, this.prev
29922 _createClass(Segment, [{
29923 key: "replaceRightSE",
29925 /* When a segment is split, the rightSE is replaced with a new sweep event */
29926 value: function replaceRightSE(newRightSE) {
29927 this.rightSE = newRightSE;
29928 this.rightSE.segment = this;
29929 this.rightSE.otherSE = this.leftSE;
29930 this.leftSE.otherSE = this.rightSE;
29934 value: function bbox() {
29935 var y1 = this.leftSE.point.y;
29936 var y2 = this.rightSE.point.y;
29939 x: this.leftSE.point.x,
29940 y: y1 < y2 ? y1 : y2
29943 x: this.rightSE.point.x,
29944 y: y1 > y2 ? y1 : y2
29948 /* A vector from the left point to the right */
29952 value: function vector() {
29954 x: this.rightSE.point.x - this.leftSE.point.x,
29955 y: this.rightSE.point.y - this.leftSE.point.y
29959 key: "isAnEndpoint",
29960 value: function isAnEndpoint(pt) {
29961 return pt.x === this.leftSE.point.x && pt.y === this.leftSE.point.y || pt.x === this.rightSE.point.x && pt.y === this.rightSE.point.y;
29963 /* Compare this segment with a point.
29965 * A point P is considered to be colinear to a segment if there
29966 * exists a distance D such that if we travel along the segment
29967 * from one * endpoint towards the other a distance D, we find
29968 * ourselves at point P.
29970 * Return value indicates:
29972 * 1: point lies above the segment (to the left of vertical)
29973 * 0: point is colinear to segment
29974 * -1: point lies below the segment (to the right of vertical)
29978 key: "comparePoint",
29979 value: function comparePoint(point) {
29980 if (this.isAnEndpoint(point)) return 0;
29981 var lPt = this.leftSE.point;
29982 var rPt = this.rightSE.point;
29983 var v = this.vector(); // Exactly vertical segments.
29985 if (lPt.x === rPt.x) {
29986 if (point.x === lPt.x) return 0;
29987 return point.x < lPt.x ? 1 : -1;
29988 } // Nearly vertical segments with an intersection.
29989 // Check to see where a point on the line with matching Y coordinate is.
29992 var yDist = (point.y - lPt.y) / v.y;
29993 var xFromYDist = lPt.x + yDist * v.x;
29994 if (point.x === xFromYDist) return 0; // General case.
29995 // Check to see where a point on the line with matching X coordinate is.
29997 var xDist = (point.x - lPt.x) / v.x;
29998 var yFromXDist = lPt.y + xDist * v.y;
29999 if (point.y === yFromXDist) return 0;
30000 return point.y < yFromXDist ? -1 : 1;
30003 * Given another segment, returns the first non-trivial intersection
30004 * between the two segments (in terms of sweep line ordering), if it exists.
30006 * A 'non-trivial' intersection is one that will cause one or both of the
30007 * segments to be split(). As such, 'trivial' vs. 'non-trivial' intersection:
30009 * * endpoint of segA with endpoint of segB --> trivial
30010 * * endpoint of segA with point along segB --> non-trivial
30011 * * endpoint of segB with point along segA --> non-trivial
30012 * * point along segA with point along segB --> non-trivial
30014 * If no non-trivial intersection exists, return null
30015 * Else, return null.
30019 key: "getIntersection",
30020 value: function getIntersection(other) {
30021 // If bboxes don't overlap, there can't be any intersections
30022 var tBbox = this.bbox();
30023 var oBbox = other.bbox();
30024 var bboxOverlap = getBboxOverlap(tBbox, oBbox);
30025 if (bboxOverlap === null) return null; // We first check to see if the endpoints can be considered intersections.
30026 // This will 'snap' intersections to endpoints if possible, and will
30027 // handle cases of colinearity.
30029 var tlp = this.leftSE.point;
30030 var trp = this.rightSE.point;
30031 var olp = other.leftSE.point;
30032 var orp = other.rightSE.point; // does each endpoint touch the other segment?
30033 // note that we restrict the 'touching' definition to only allow segments
30034 // to touch endpoints that lie forward from where we are in the sweep line pass
30036 var touchesOtherLSE = isInBbox(tBbox, olp) && this.comparePoint(olp) === 0;
30037 var touchesThisLSE = isInBbox(oBbox, tlp) && other.comparePoint(tlp) === 0;
30038 var touchesOtherRSE = isInBbox(tBbox, orp) && this.comparePoint(orp) === 0;
30039 var touchesThisRSE = isInBbox(oBbox, trp) && other.comparePoint(trp) === 0; // do left endpoints match?
30041 if (touchesThisLSE && touchesOtherLSE) {
30042 // these two cases are for colinear segments with matching left
30043 // endpoints, and one segment being longer than the other
30044 if (touchesThisRSE && !touchesOtherRSE) return trp;
30045 if (!touchesThisRSE && touchesOtherRSE) return orp; // either the two segments match exactly (two trival intersections)
30046 // or just on their left endpoint (one trivial intersection
30049 } // does this left endpoint matches (other doesn't)
30052 if (touchesThisLSE) {
30053 // check for segments that just intersect on opposing endpoints
30054 if (touchesOtherRSE) {
30055 if (tlp.x === orp.x && tlp.y === orp.y) return null;
30056 } // t-intersection on left endpoint
30060 } // does other left endpoint matches (this doesn't)
30063 if (touchesOtherLSE) {
30064 // check for segments that just intersect on opposing endpoints
30065 if (touchesThisRSE) {
30066 if (trp.x === olp.x && trp.y === olp.y) return null;
30067 } // t-intersection on left endpoint
30071 } // trivial intersection on right endpoints
30074 if (touchesThisRSE && touchesOtherRSE) return null; // t-intersections on just one right endpoint
30076 if (touchesThisRSE) return trp;
30077 if (touchesOtherRSE) return orp; // None of our endpoints intersect. Look for a general intersection between
30078 // infinite lines laid over the segments
30080 var pt = intersection(tlp, this.vector(), olp, other.vector()); // are the segments parrallel? Note that if they were colinear with overlap,
30081 // they would have an endpoint intersection and that case was already handled above
30083 if (pt === null) return null; // is the intersection found between the lines not on the segments?
30085 if (!isInBbox(bboxOverlap, pt)) return null; // round the the computed point if needed
30087 return rounder.round(pt.x, pt.y);
30090 * Split the given segment into multiple segments on the given points.
30091 * * Each existing segment will retain its leftSE and a new rightSE will be
30092 * generated for it.
30093 * * A new segment will be generated which will adopt the original segment's
30094 * rightSE, and a new leftSE will be generated for it.
30095 * * If there are more than two points given to split on, new segments
30096 * in the middle will be generated with new leftSE and rightSE's.
30097 * * An array of the newly generated SweepEvents will be returned.
30099 * Warning: input array of points is modified
30104 value: function split(point) {
30105 var newEvents = [];
30106 var alreadyLinked = point.events !== undefined;
30107 var newLeftSE = new SweepEvent(point, true);
30108 var newRightSE = new SweepEvent(point, false);
30109 var oldRightSE = this.rightSE;
30110 this.replaceRightSE(newRightSE);
30111 newEvents.push(newRightSE);
30112 newEvents.push(newLeftSE);
30113 var newSeg = new Segment(newLeftSE, oldRightSE, this.rings.slice(), this.windings.slice()); // when splitting a nearly vertical downward-facing segment,
30114 // sometimes one of the resulting new segments is vertical, in which
30115 // case its left and right events may need to be swapped
30117 if (SweepEvent.comparePoints(newSeg.leftSE.point, newSeg.rightSE.point) > 0) {
30118 newSeg.swapEvents();
30121 if (SweepEvent.comparePoints(this.leftSE.point, this.rightSE.point) > 0) {
30123 } // in the point we just used to create new sweep events with was already
30124 // linked to other events, we need to check if either of the affected
30125 // segments should be consumed
30128 if (alreadyLinked) {
30129 newLeftSE.checkForConsuming();
30130 newRightSE.checkForConsuming();
30135 /* Swap which event is left and right */
30139 value: function swapEvents() {
30140 var tmpEvt = this.rightSE;
30141 this.rightSE = this.leftSE;
30142 this.leftSE = tmpEvt;
30143 this.leftSE.isLeft = true;
30144 this.rightSE.isLeft = false;
30146 for (var i = 0, iMax = this.windings.length; i < iMax; i++) {
30147 this.windings[i] *= -1;
30150 /* Consume another segment. We take their rings under our wing
30151 * and mark them as consumed. Use for perfectly overlapping segments */
30155 value: function consume(other) {
30156 var consumer = this;
30157 var consumee = other;
30159 while (consumer.consumedBy) {
30160 consumer = consumer.consumedBy;
30163 while (consumee.consumedBy) {
30164 consumee = consumee.consumedBy;
30167 var cmp = Segment.compare(consumer, consumee);
30168 if (cmp === 0) return; // already consumed
30169 // the winner of the consumption is the earlier segment
30170 // according to sweep line ordering
30173 var tmp = consumer;
30174 consumer = consumee;
30176 } // make sure a segment doesn't consume it's prev
30179 if (consumer.prev === consumee) {
30180 var _tmp = consumer;
30181 consumer = consumee;
30185 for (var i = 0, iMax = consumee.rings.length; i < iMax; i++) {
30186 var ring = consumee.rings[i];
30187 var winding = consumee.windings[i];
30188 var index = consumer.rings.indexOf(ring);
30190 if (index === -1) {
30191 consumer.rings.push(ring);
30192 consumer.windings.push(winding);
30193 } else consumer.windings[index] += winding;
30196 consumee.rings = null;
30197 consumee.windings = null;
30198 consumee.consumedBy = consumer; // mark sweep events consumed as to maintain ordering in sweep event queue
30200 consumee.leftSE.consumedBy = consumer.leftSE;
30201 consumee.rightSE.consumedBy = consumer.rightSE;
30203 /* The first segment previous segment chain that is in the result */
30206 key: "prevInResult",
30207 value: function prevInResult() {
30208 if (this._prevInResult !== undefined) return this._prevInResult;
30209 if (!this.prev) this._prevInResult = null;else if (this.prev.isInResult()) this._prevInResult = this.prev;else this._prevInResult = this.prev.prevInResult();
30210 return this._prevInResult;
30213 key: "beforeState",
30214 value: function beforeState() {
30215 if (this._beforeState !== undefined) return this._beforeState;
30216 if (!this.prev) this._beforeState = {
30221 var seg = this.prev.consumedBy || this.prev;
30222 this._beforeState = seg.afterState();
30224 return this._beforeState;
30228 value: function afterState() {
30229 if (this._afterState !== undefined) return this._afterState;
30230 var beforeState = this.beforeState();
30231 this._afterState = {
30232 rings: beforeState.rings.slice(0),
30233 windings: beforeState.windings.slice(0),
30236 var ringsAfter = this._afterState.rings;
30237 var windingsAfter = this._afterState.windings;
30238 var mpsAfter = this._afterState.multiPolys; // calculate ringsAfter, windingsAfter
30240 for (var i = 0, iMax = this.rings.length; i < iMax; i++) {
30241 var ring = this.rings[i];
30242 var winding = this.windings[i];
30243 var index = ringsAfter.indexOf(ring);
30245 if (index === -1) {
30246 ringsAfter.push(ring);
30247 windingsAfter.push(winding);
30248 } else windingsAfter[index] += winding;
30249 } // calcualte polysAfter
30252 var polysAfter = [];
30253 var polysExclude = [];
30255 for (var _i = 0, _iMax = ringsAfter.length; _i < _iMax; _i++) {
30256 if (windingsAfter[_i] === 0) continue; // non-zero rule
30258 var _ring = ringsAfter[_i];
30259 var poly = _ring.poly;
30260 if (polysExclude.indexOf(poly) !== -1) continue;
30261 if (_ring.isExterior) polysAfter.push(poly);else {
30262 if (polysExclude.indexOf(poly) === -1) polysExclude.push(poly);
30264 var _index = polysAfter.indexOf(_ring.poly);
30266 if (_index !== -1) polysAfter.splice(_index, 1);
30268 } // calculate multiPolysAfter
30271 for (var _i2 = 0, _iMax2 = polysAfter.length; _i2 < _iMax2; _i2++) {
30272 var mp = polysAfter[_i2].multiPoly;
30273 if (mpsAfter.indexOf(mp) === -1) mpsAfter.push(mp);
30276 return this._afterState;
30278 /* Is this segment part of the final result? */
30282 value: function isInResult() {
30283 // if we've been consumed, we're not in the result
30284 if (this.consumedBy) return false;
30285 if (this._isInResult !== undefined) return this._isInResult;
30286 var mpsBefore = this.beforeState().multiPolys;
30287 var mpsAfter = this.afterState().multiPolys;
30289 switch (operation.type) {
30292 // UNION - included iff:
30293 // * On one side of us there is 0 poly interiors AND
30294 // * On the other side there is 1 or more.
30295 var noBefores = mpsBefore.length === 0;
30296 var noAfters = mpsAfter.length === 0;
30297 this._isInResult = noBefores !== noAfters;
30301 case 'intersection':
30303 // INTERSECTION - included iff:
30304 // * on one side of us all multipolys are rep. with poly interiors AND
30305 // * on the other side of us, not all multipolys are repsented
30306 // with poly interiors
30310 if (mpsBefore.length < mpsAfter.length) {
30311 least = mpsBefore.length;
30312 most = mpsAfter.length;
30314 least = mpsAfter.length;
30315 most = mpsBefore.length;
30318 this._isInResult = most === operation.numMultiPolys && least < most;
30324 // XOR - included iff:
30325 // * the difference between the number of multipolys represented
30326 // with poly interiors on our two sides is an odd number
30327 var diff = Math.abs(mpsBefore.length - mpsAfter.length);
30328 this._isInResult = diff % 2 === 1;
30334 // DIFFERENCE included iff:
30335 // * on exactly one side, we have just the subject
30336 var isJustSubject = function isJustSubject(mps) {
30337 return mps.length === 1 && mps[0].isSubject;
30340 this._isInResult = isJustSubject(mpsBefore) !== isJustSubject(mpsAfter);
30345 throw new Error("Unrecognized operation type found ".concat(operation.type));
30348 return this._isInResult;
30352 value: function fromRing(pt1, pt2, ring) {
30353 var leftPt, rightPt, winding; // ordering the two points according to sweep line ordering
30355 var cmpPts = SweepEvent.comparePoints(pt1, pt2);
30361 } else if (cmpPts > 0) {
30365 } else throw new Error("Tried to create degenerate segment at [".concat(pt1.x, ", ").concat(pt1.y, "]"));
30367 var leftSE = new SweepEvent(leftPt, true);
30368 var rightSE = new SweepEvent(rightPt, false);
30369 return new Segment(leftSE, rightSE, [ring], [winding]);
30376 var RingIn = /*#__PURE__*/function () {
30377 function RingIn(geomRing, poly, isExterior) {
30378 _classCallCheck(this, RingIn);
30380 if (!Array.isArray(geomRing) || geomRing.length === 0) {
30381 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30385 this.isExterior = isExterior;
30386 this.segments = [];
30388 if (typeof geomRing[0][0] !== 'number' || typeof geomRing[0][1] !== 'number') {
30389 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30392 var firstPoint = rounder.round(geomRing[0][0], geomRing[0][1]);
30403 var prevPoint = firstPoint;
30405 for (var i = 1, iMax = geomRing.length; i < iMax; i++) {
30406 if (typeof geomRing[i][0] !== 'number' || typeof geomRing[i][1] !== 'number') {
30407 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30410 var point = rounder.round(geomRing[i][0], geomRing[i][1]); // skip repeated points
30412 if (point.x === prevPoint.x && point.y === prevPoint.y) continue;
30413 this.segments.push(Segment.fromRing(prevPoint, point, this));
30414 if (point.x < this.bbox.ll.x) this.bbox.ll.x = point.x;
30415 if (point.y < this.bbox.ll.y) this.bbox.ll.y = point.y;
30416 if (point.x > this.bbox.ur.x) this.bbox.ur.x = point.x;
30417 if (point.y > this.bbox.ur.y) this.bbox.ur.y = point.y;
30419 } // add segment from last to first if last is not the same as first
30422 if (firstPoint.x !== prevPoint.x || firstPoint.y !== prevPoint.y) {
30423 this.segments.push(Segment.fromRing(prevPoint, firstPoint, this));
30427 _createClass(RingIn, [{
30428 key: "getSweepEvents",
30429 value: function getSweepEvents() {
30430 var sweepEvents = [];
30432 for (var i = 0, iMax = this.segments.length; i < iMax; i++) {
30433 var segment = this.segments[i];
30434 sweepEvents.push(segment.leftSE);
30435 sweepEvents.push(segment.rightSE);
30438 return sweepEvents;
30445 var PolyIn = /*#__PURE__*/function () {
30446 function PolyIn(geomPoly, multiPoly) {
30447 _classCallCheck(this, PolyIn);
30449 if (!Array.isArray(geomPoly)) {
30450 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30453 this.exteriorRing = new RingIn(geomPoly[0], this, true); // copy by value
30457 x: this.exteriorRing.bbox.ll.x,
30458 y: this.exteriorRing.bbox.ll.y
30461 x: this.exteriorRing.bbox.ur.x,
30462 y: this.exteriorRing.bbox.ur.y
30465 this.interiorRings = [];
30467 for (var i = 1, iMax = geomPoly.length; i < iMax; i++) {
30468 var ring = new RingIn(geomPoly[i], this, false);
30469 if (ring.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = ring.bbox.ll.x;
30470 if (ring.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = ring.bbox.ll.y;
30471 if (ring.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = ring.bbox.ur.x;
30472 if (ring.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = ring.bbox.ur.y;
30473 this.interiorRings.push(ring);
30476 this.multiPoly = multiPoly;
30479 _createClass(PolyIn, [{
30480 key: "getSweepEvents",
30481 value: function getSweepEvents() {
30482 var sweepEvents = this.exteriorRing.getSweepEvents();
30484 for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
30485 var ringSweepEvents = this.interiorRings[i].getSweepEvents();
30487 for (var j = 0, jMax = ringSweepEvents.length; j < jMax; j++) {
30488 sweepEvents.push(ringSweepEvents[j]);
30492 return sweepEvents;
30499 var MultiPolyIn = /*#__PURE__*/function () {
30500 function MultiPolyIn(geom, isSubject) {
30501 _classCallCheck(this, MultiPolyIn);
30503 if (!Array.isArray(geom)) {
30504 throw new Error('Input geometry is not a valid Polygon or MultiPolygon');
30508 // if the input looks like a polygon, convert it to a multipolygon
30509 if (typeof geom[0][0][0] === 'number') geom = [geom];
30510 } catch (ex) {// The input is either malformed or has empty arrays.
30511 // In either case, it will be handled later on.
30517 x: Number.POSITIVE_INFINITY,
30518 y: Number.POSITIVE_INFINITY
30521 x: Number.NEGATIVE_INFINITY,
30522 y: Number.NEGATIVE_INFINITY
30526 for (var i = 0, iMax = geom.length; i < iMax; i++) {
30527 var poly = new PolyIn(geom[i], this);
30528 if (poly.bbox.ll.x < this.bbox.ll.x) this.bbox.ll.x = poly.bbox.ll.x;
30529 if (poly.bbox.ll.y < this.bbox.ll.y) this.bbox.ll.y = poly.bbox.ll.y;
30530 if (poly.bbox.ur.x > this.bbox.ur.x) this.bbox.ur.x = poly.bbox.ur.x;
30531 if (poly.bbox.ur.y > this.bbox.ur.y) this.bbox.ur.y = poly.bbox.ur.y;
30532 this.polys.push(poly);
30535 this.isSubject = isSubject;
30538 _createClass(MultiPolyIn, [{
30539 key: "getSweepEvents",
30540 value: function getSweepEvents() {
30541 var sweepEvents = [];
30543 for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
30544 var polySweepEvents = this.polys[i].getSweepEvents();
30546 for (var j = 0, jMax = polySweepEvents.length; j < jMax; j++) {
30547 sweepEvents.push(polySweepEvents[j]);
30551 return sweepEvents;
30555 return MultiPolyIn;
30558 var RingOut = /*#__PURE__*/function () {
30559 _createClass(RingOut, null, [{
30562 /* Given the segments from the sweep line pass, compute & return a series
30563 * of closed rings from all the segments marked to be part of the result */
30564 value: function factory(allSegments) {
30567 for (var i = 0, iMax = allSegments.length; i < iMax; i++) {
30568 var segment = allSegments[i];
30569 if (!segment.isInResult() || segment.ringOut) continue;
30570 var prevEvent = null;
30571 var event = segment.leftSE;
30572 var nextEvent = segment.rightSE;
30573 var events = [event];
30574 var startingPoint = event.point;
30575 var intersectionLEs = [];
30576 /* Walk the chain of linked events to form a closed ring */
30581 events.push(event);
30582 /* Is the ring complete? */
30584 if (event.point === startingPoint) break;
30587 var availableLEs = event.getAvailableLinkedEvents();
30588 /* Did we hit a dead end? This shouldn't happen. Indicates some earlier
30589 * part of the algorithm malfunctioned... please file a bug report. */
30591 if (availableLEs.length === 0) {
30592 var firstPt = events[0].point;
30593 var lastPt = events[events.length - 1].point;
30594 throw new Error("Unable to complete output ring starting at [".concat(firstPt.x, ",") + " ".concat(firstPt.y, "]. Last matching segment found ends at") + " [".concat(lastPt.x, ", ").concat(lastPt.y, "]."));
30596 /* Only one way to go, so cotinue on the path */
30599 if (availableLEs.length === 1) {
30600 nextEvent = availableLEs[0].otherSE;
30603 /* We must have an intersection. Check for a completed loop */
30606 var indexLE = null;
30608 for (var j = 0, jMax = intersectionLEs.length; j < jMax; j++) {
30609 if (intersectionLEs[j].point === event.point) {
30614 /* Found a completed loop. Cut that off and make a ring */
30617 if (indexLE !== null) {
30618 var intersectionLE = intersectionLEs.splice(indexLE)[0];
30619 var ringEvents = events.splice(intersectionLE.index);
30620 ringEvents.unshift(ringEvents[0].otherSE);
30621 ringsOut.push(new RingOut(ringEvents.reverse()));
30624 /* register the intersection */
30627 intersectionLEs.push({
30628 index: events.length,
30631 /* Choose the left-most option to continue the walk */
30633 var comparator = event.getLeftmostComparator(prevEvent);
30634 nextEvent = availableLEs.sort(comparator)[0].otherSE;
30639 ringsOut.push(new RingOut(events));
30646 function RingOut(events) {
30647 _classCallCheck(this, RingOut);
30649 this.events = events;
30651 for (var i = 0, iMax = events.length; i < iMax; i++) {
30652 events[i].segment.ringOut = this;
30658 _createClass(RingOut, [{
30660 value: function getGeom() {
30661 // Remove superfluous points (ie extra points along a straight line),
30662 var prevPt = this.events[0].point;
30663 var points = [prevPt];
30665 for (var i = 1, iMax = this.events.length - 1; i < iMax; i++) {
30666 var _pt = this.events[i].point;
30667 var _nextPt = this.events[i + 1].point;
30668 if (compareVectorAngles(_pt, prevPt, _nextPt) === 0) continue;
30671 } // ring was all (within rounding error of angle calc) colinear points
30674 if (points.length === 1) return null; // check if the starting point is necessary
30676 var pt = points[0];
30677 var nextPt = points[1];
30678 if (compareVectorAngles(pt, prevPt, nextPt) === 0) points.shift();
30679 points.push(points[0]);
30680 var step = this.isExteriorRing() ? 1 : -1;
30681 var iStart = this.isExteriorRing() ? 0 : points.length - 1;
30682 var iEnd = this.isExteriorRing() ? points.length : -1;
30683 var orderedPoints = [];
30685 for (var _i = iStart; _i != iEnd; _i += step) {
30686 orderedPoints.push([points[_i].x, points[_i].y]);
30689 return orderedPoints;
30692 key: "isExteriorRing",
30693 value: function isExteriorRing() {
30694 if (this._isExteriorRing === undefined) {
30695 var enclosing = this.enclosingRing();
30696 this._isExteriorRing = enclosing ? !enclosing.isExteriorRing() : true;
30699 return this._isExteriorRing;
30702 key: "enclosingRing",
30703 value: function enclosingRing() {
30704 if (this._enclosingRing === undefined) {
30705 this._enclosingRing = this._calcEnclosingRing();
30708 return this._enclosingRing;
30710 /* Returns the ring that encloses this one, if any */
30713 key: "_calcEnclosingRing",
30714 value: function _calcEnclosingRing() {
30715 // start with the ealier sweep line event so that the prevSeg
30716 // chain doesn't lead us inside of a loop of ours
30717 var leftMostEvt = this.events[0];
30719 for (var i = 1, iMax = this.events.length; i < iMax; i++) {
30720 var evt = this.events[i];
30721 if (SweepEvent.compare(leftMostEvt, evt) > 0) leftMostEvt = evt;
30724 var prevSeg = leftMostEvt.segment.prevInResult();
30725 var prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
30728 // no segment found, thus no ring can enclose us
30729 if (!prevSeg) return null; // no segments below prev segment found, thus the ring of the prev
30730 // segment must loop back around and enclose us
30732 if (!prevPrevSeg) return prevSeg.ringOut; // if the two segments are of different rings, the ring of the prev
30733 // segment must either loop around us or the ring of the prev prev
30734 // seg, which would make us and the ring of the prev peers
30736 if (prevPrevSeg.ringOut !== prevSeg.ringOut) {
30737 if (prevPrevSeg.ringOut.enclosingRing() !== prevSeg.ringOut) {
30738 return prevSeg.ringOut;
30739 } else return prevSeg.ringOut.enclosingRing();
30740 } // two segments are from the same ring, so this was a penisula
30741 // of that ring. iterate downward, keep searching
30744 prevSeg = prevPrevSeg.prevInResult();
30745 prevPrevSeg = prevSeg ? prevSeg.prevInResult() : null;
30753 var PolyOut = /*#__PURE__*/function () {
30754 function PolyOut(exteriorRing) {
30755 _classCallCheck(this, PolyOut);
30757 this.exteriorRing = exteriorRing;
30758 exteriorRing.poly = this;
30759 this.interiorRings = [];
30762 _createClass(PolyOut, [{
30763 key: "addInterior",
30764 value: function addInterior(ring) {
30765 this.interiorRings.push(ring);
30770 value: function getGeom() {
30771 var geom = [this.exteriorRing.getGeom()]; // exterior ring was all (within rounding error of angle calc) colinear points
30773 if (geom[0] === null) return null;
30775 for (var i = 0, iMax = this.interiorRings.length; i < iMax; i++) {
30776 var ringGeom = this.interiorRings[i].getGeom(); // interior ring was all (within rounding error of angle calc) colinear points
30778 if (ringGeom === null) continue;
30779 geom.push(ringGeom);
30789 var MultiPolyOut = /*#__PURE__*/function () {
30790 function MultiPolyOut(rings) {
30791 _classCallCheck(this, MultiPolyOut);
30793 this.rings = rings;
30794 this.polys = this._composePolys(rings);
30797 _createClass(MultiPolyOut, [{
30799 value: function getGeom() {
30802 for (var i = 0, iMax = this.polys.length; i < iMax; i++) {
30803 var polyGeom = this.polys[i].getGeom(); // exterior ring was all (within rounding error of angle calc) colinear points
30805 if (polyGeom === null) continue;
30806 geom.push(polyGeom);
30812 key: "_composePolys",
30813 value: function _composePolys(rings) {
30816 for (var i = 0, iMax = rings.length; i < iMax; i++) {
30817 var ring = rings[i];
30818 if (ring.poly) continue;
30819 if (ring.isExteriorRing()) polys.push(new PolyOut(ring));else {
30820 var enclosingRing = ring.enclosingRing();
30821 if (!enclosingRing.poly) polys.push(new PolyOut(enclosingRing));
30822 enclosingRing.poly.addInterior(ring);
30830 return MultiPolyOut;
30833 * NOTE: We must be careful not to change any segments while
30834 * they are in the SplayTree. AFAIK, there's no way to tell
30835 * the tree to rebalance itself - thus before splitting
30836 * a segment that's in the tree, we remove it from the tree,
30837 * do the split, then re-insert it. (Even though splitting a
30838 * segment *shouldn't* change its correct position in the
30839 * sweep line tree, the reality is because of rounding errors,
30840 * it sometimes does.)
30844 var SweepLine = /*#__PURE__*/function () {
30845 function SweepLine(queue) {
30846 var comparator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Segment.compare;
30848 _classCallCheck(this, SweepLine);
30850 this.queue = queue;
30851 this.tree = new Tree(comparator);
30852 this.segments = [];
30855 _createClass(SweepLine, [{
30857 value: function process(event) {
30858 var segment = event.segment;
30859 var newEvents = []; // if we've already been consumed by another segment,
30860 // clean up our body parts and get out
30862 if (event.consumedBy) {
30863 if (event.isLeft) this.queue.remove(event.otherSE);else this.tree.remove(segment);
30867 var node = event.isLeft ? this.tree.insert(segment) : this.tree.find(segment);
30868 if (!node) throw new Error("Unable to find segment #".concat(segment.id, " ") + "[".concat(segment.leftSE.point.x, ", ").concat(segment.leftSE.point.y, "] -> ") + "[".concat(segment.rightSE.point.x, ", ").concat(segment.rightSE.point.y, "] ") + 'in SweepLine tree. Please submit a bug report.');
30869 var prevNode = node;
30870 var nextNode = node;
30871 var prevSeg = undefined;
30872 var nextSeg = undefined; // skip consumed segments still in tree
30874 while (prevSeg === undefined) {
30875 prevNode = this.tree.prev(prevNode);
30876 if (prevNode === null) prevSeg = null;else if (prevNode.key.consumedBy === undefined) prevSeg = prevNode.key;
30877 } // skip consumed segments still in tree
30880 while (nextSeg === undefined) {
30881 nextNode = this.tree.next(nextNode);
30882 if (nextNode === null) nextSeg = null;else if (nextNode.key.consumedBy === undefined) nextSeg = nextNode.key;
30885 if (event.isLeft) {
30886 // Check for intersections against the previous segment in the sweep line
30887 var prevMySplitter = null;
30890 var prevInter = prevSeg.getIntersection(segment);
30892 if (prevInter !== null) {
30893 if (!segment.isAnEndpoint(prevInter)) prevMySplitter = prevInter;
30895 if (!prevSeg.isAnEndpoint(prevInter)) {
30896 var newEventsFromSplit = this._splitSafely(prevSeg, prevInter);
30898 for (var i = 0, iMax = newEventsFromSplit.length; i < iMax; i++) {
30899 newEvents.push(newEventsFromSplit[i]);
30903 } // Check for intersections against the next segment in the sweep line
30906 var nextMySplitter = null;
30909 var nextInter = nextSeg.getIntersection(segment);
30911 if (nextInter !== null) {
30912 if (!segment.isAnEndpoint(nextInter)) nextMySplitter = nextInter;
30914 if (!nextSeg.isAnEndpoint(nextInter)) {
30915 var _newEventsFromSplit = this._splitSafely(nextSeg, nextInter);
30917 for (var _i = 0, _iMax = _newEventsFromSplit.length; _i < _iMax; _i++) {
30918 newEvents.push(_newEventsFromSplit[_i]);
30922 } // For simplicity, even if we find more than one intersection we only
30923 // spilt on the 'earliest' (sweep-line style) of the intersections.
30924 // The other intersection will be handled in a future process().
30927 if (prevMySplitter !== null || nextMySplitter !== null) {
30928 var mySplitter = null;
30929 if (prevMySplitter === null) mySplitter = nextMySplitter;else if (nextMySplitter === null) mySplitter = prevMySplitter;else {
30930 var cmpSplitters = SweepEvent.comparePoints(prevMySplitter, nextMySplitter);
30931 mySplitter = cmpSplitters <= 0 ? prevMySplitter : nextMySplitter;
30932 } // Rounding errors can cause changes in ordering,
30933 // so remove afected segments and right sweep events before splitting
30935 this.queue.remove(segment.rightSE);
30936 newEvents.push(segment.rightSE);
30938 var _newEventsFromSplit2 = segment.split(mySplitter);
30940 for (var _i2 = 0, _iMax2 = _newEventsFromSplit2.length; _i2 < _iMax2; _i2++) {
30941 newEvents.push(_newEventsFromSplit2[_i2]);
30945 if (newEvents.length > 0) {
30946 // We found some intersections, so re-do the current event to
30947 // make sure sweep line ordering is totally consistent for later
30948 // use with the segment 'prev' pointers
30949 this.tree.remove(segment);
30950 newEvents.push(event);
30952 // done with left event
30953 this.segments.push(segment);
30954 segment.prev = prevSeg;
30958 // since we're about to be removed from the sweep line, check for
30959 // intersections between our previous and next segments
30960 if (prevSeg && nextSeg) {
30961 var inter = prevSeg.getIntersection(nextSeg);
30963 if (inter !== null) {
30964 if (!prevSeg.isAnEndpoint(inter)) {
30965 var _newEventsFromSplit3 = this._splitSafely(prevSeg, inter);
30967 for (var _i3 = 0, _iMax3 = _newEventsFromSplit3.length; _i3 < _iMax3; _i3++) {
30968 newEvents.push(_newEventsFromSplit3[_i3]);
30972 if (!nextSeg.isAnEndpoint(inter)) {
30973 var _newEventsFromSplit4 = this._splitSafely(nextSeg, inter);
30975 for (var _i4 = 0, _iMax4 = _newEventsFromSplit4.length; _i4 < _iMax4; _i4++) {
30976 newEvents.push(_newEventsFromSplit4[_i4]);
30982 this.tree.remove(segment);
30987 /* Safely split a segment that is currently in the datastructures
30988 * IE - a segment other than the one that is currently being processed. */
30991 key: "_splitSafely",
30992 value: function _splitSafely(seg, pt) {
30993 // Rounding errors can cause changes in ordering,
30994 // so remove afected segments and right sweep events before splitting
30995 // removeNode() doesn't work, so have re-find the seg
30996 // https://github.com/w8r/splay-tree/pull/5
30997 this.tree.remove(seg);
30998 var rightSE = seg.rightSE;
30999 this.queue.remove(rightSE);
31000 var newEvents = seg.split(pt);
31001 newEvents.push(rightSE); // splitting can trigger consumption
31003 if (seg.consumedBy === undefined) this.tree.insert(seg);
31011 var POLYGON_CLIPPING_MAX_QUEUE_SIZE = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_QUEUE_SIZE || 1000000;
31012 var POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS = typeof process !== 'undefined' && process.env.POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS || 1000000;
31014 var Operation = /*#__PURE__*/function () {
31015 function Operation() {
31016 _classCallCheck(this, Operation);
31019 _createClass(Operation, [{
31021 value: function run(type, geom, moreGeoms) {
31022 operation.type = type;
31024 /* Convert inputs to MultiPoly objects */
31026 var multipolys = [new MultiPolyIn(geom, true)];
31028 for (var i = 0, iMax = moreGeoms.length; i < iMax; i++) {
31029 multipolys.push(new MultiPolyIn(moreGeoms[i], false));
31032 operation.numMultiPolys = multipolys.length;
31033 /* BBox optimization for difference operation
31034 * If the bbox of a multipolygon that's part of the clipping doesn't
31035 * intersect the bbox of the subject at all, we can just drop that
31038 if (operation.type === 'difference') {
31039 // in place removal
31040 var subject = multipolys[0];
31043 while (_i < multipolys.length) {
31044 if (getBboxOverlap(multipolys[_i].bbox, subject.bbox) !== null) _i++;else multipolys.splice(_i, 1);
31047 /* BBox optimization for intersection operation
31048 * If we can find any pair of multipolygons whose bbox does not overlap,
31049 * then the result will be empty. */
31052 if (operation.type === 'intersection') {
31053 // TODO: this is O(n^2) in number of polygons. By sorting the bboxes,
31054 // it could be optimized to O(n * ln(n))
31055 for (var _i2 = 0, _iMax = multipolys.length; _i2 < _iMax; _i2++) {
31056 var mpA = multipolys[_i2];
31058 for (var j = _i2 + 1, jMax = multipolys.length; j < jMax; j++) {
31059 if (getBboxOverlap(mpA.bbox, multipolys[j].bbox) === null) return [];
31063 /* Put segment endpoints in a priority queue */
31066 var queue = new Tree(SweepEvent.compare);
31068 for (var _i3 = 0, _iMax2 = multipolys.length; _i3 < _iMax2; _i3++) {
31069 var sweepEvents = multipolys[_i3].getSweepEvents();
31071 for (var _j = 0, _jMax = sweepEvents.length; _j < _jMax; _j++) {
31072 queue.insert(sweepEvents[_j]);
31074 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
31075 // prevents an infinite loop, an otherwise common manifestation of bugs
31076 throw new Error('Infinite loop when putting segment endpoints in a priority queue ' + '(queue size too big). Please file a bug report.');
31080 /* Pass the sweep line over those endpoints */
31083 var sweepLine = new SweepLine(queue);
31084 var prevQueueSize = queue.size;
31085 var node = queue.pop();
31088 var evt = node.key;
31090 if (queue.size === prevQueueSize) {
31091 // prevents an infinite loop, an otherwise common manifestation of bugs
31092 var seg = evt.segment;
31093 throw new Error("Unable to pop() ".concat(evt.isLeft ? 'left' : 'right', " SweepEvent ") + "[".concat(evt.point.x, ", ").concat(evt.point.y, "] from segment #").concat(seg.id, " ") + "[".concat(seg.leftSE.point.x, ", ").concat(seg.leftSE.point.y, "] -> ") + "[".concat(seg.rightSE.point.x, ", ").concat(seg.rightSE.point.y, "] from queue. ") + 'Please file a bug report.');
31096 if (queue.size > POLYGON_CLIPPING_MAX_QUEUE_SIZE) {
31097 // prevents an infinite loop, an otherwise common manifestation of bugs
31098 throw new Error('Infinite loop when passing sweep line over endpoints ' + '(queue size too big). Please file a bug report.');
31101 if (sweepLine.segments.length > POLYGON_CLIPPING_MAX_SWEEPLINE_SEGMENTS) {
31102 // prevents an infinite loop, an otherwise common manifestation of bugs
31103 throw new Error('Infinite loop when passing sweep line over endpoints ' + '(too many sweep line segments). Please file a bug report.');
31106 var newEvents = sweepLine.process(evt);
31108 for (var _i4 = 0, _iMax3 = newEvents.length; _i4 < _iMax3; _i4++) {
31109 var _evt = newEvents[_i4];
31110 if (_evt.consumedBy === undefined) queue.insert(_evt);
31113 prevQueueSize = queue.size;
31114 node = queue.pop();
31115 } // free some memory we don't need anymore
31119 /* Collect and compile segments we're keeping into a multipolygon */
31121 var ringsOut = RingOut.factory(sweepLine.segments);
31122 var result = new MultiPolyOut(ringsOut);
31123 return result.getGeom();
31128 }(); // singleton available by import
31131 var operation = new Operation();
31133 var union = function union(geom) {
31134 for (var _len = arguments.length, moreGeoms = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
31135 moreGeoms[_key - 1] = arguments[_key];
31138 return operation.run('union', geom, moreGeoms);
31141 var intersection$1 = function intersection(geom) {
31142 for (var _len2 = arguments.length, moreGeoms = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
31143 moreGeoms[_key2 - 1] = arguments[_key2];
31146 return operation.run('intersection', geom, moreGeoms);
31149 var xor = function xor(geom) {
31150 for (var _len3 = arguments.length, moreGeoms = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
31151 moreGeoms[_key3 - 1] = arguments[_key3];
31154 return operation.run('xor', geom, moreGeoms);
31157 var difference = function difference(subjectGeom) {
31158 for (var _len4 = arguments.length, clippingGeoms = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
31159 clippingGeoms[_key4 - 1] = arguments[_key4];
31162 return operation.run('difference', subjectGeom, clippingGeoms);
31167 intersection: intersection$1,
31169 difference: difference
31172 var geojsonPrecision = {exports: {}};
31175 function parse(t, coordinatePrecision, extrasPrecision) {
31176 function point(p) {
31177 return p.map(function (e, index) {
31179 return 1 * e.toFixed(coordinatePrecision);
31181 return 1 * e.toFixed(extrasPrecision);
31186 function multi(l) {
31187 return l.map(point);
31191 return p.map(multi);
31194 function multiPoly(m) {
31195 return m.map(poly);
31198 function geometry(obj) {
31203 switch (obj.type) {
31205 obj.coordinates = point(obj.coordinates);
31210 obj.coordinates = multi(obj.coordinates);
31214 case "MultiLineString":
31215 obj.coordinates = poly(obj.coordinates);
31218 case "MultiPolygon":
31219 obj.coordinates = multiPoly(obj.coordinates);
31222 case "GeometryCollection":
31223 obj.geometries = obj.geometries.map(geometry);
31231 function feature(obj) {
31232 obj.geometry = geometry(obj.geometry);
31236 function featureCollection(f) {
31237 f.features = f.features.map(feature);
31241 function geometryCollection(g) {
31242 g.geometries = g.geometries.map(geometry);
31254 case "GeometryCollection":
31255 return geometryCollection(t);
31257 case "FeatureCollection":
31258 return featureCollection(t);
31264 case "MultiPolygon":
31265 case "MultiLineString":
31266 return geometry(t);
31273 geojsonPrecision.exports = parse;
31274 geojsonPrecision.exports.parse = parse;
31277 var precision = geojsonPrecision.exports;
31280 var fails$5 = fails$N;
31281 var toObject = toObject$i;
31282 var toPrimitive = toPrimitive$7;
31284 var FORCED$3 = fails$5(function () {
31285 return new Date(NaN).toJSON() !== null
31286 || Date.prototype.toJSON.call({ toISOString: function () { return 1; } }) !== 1;
31289 // `Date.prototype.toJSON` method
31290 // https://tc39.es/ecma262/#sec-date.prototype.tojson
31291 $$d({ target: 'Date', proto: true, forced: FORCED$3 }, {
31292 // eslint-disable-next-line no-unused-vars -- required for `.length`
31293 toJSON: function toJSON(key) {
31294 var O = toObject(this);
31295 var pv = toPrimitive(O);
31296 return typeof pv == 'number' && !isFinite(pv) ? null : O.toISOString();
31302 // `URL.prototype.toJSON` method
31303 // https://url.spec.whatwg.org/#dom-url-tojson
31304 $$c({ target: 'URL', proto: true, enumerable: true }, {
31305 toJSON: function toJSON() {
31306 return URL.prototype.toString.call(this);
31310 function isObject$3(obj) {
31311 return _typeof(obj) === 'object' && obj !== null;
31314 function forEach(obj, cb) {
31315 if (Array.isArray(obj)) {
31317 } else if (isObject$3(obj)) {
31318 Object.keys(obj).forEach(function (key) {
31319 var val = obj[key];
31325 function getTreeDepth(obj) {
31328 if (Array.isArray(obj) || isObject$3(obj)) {
31329 forEach(obj, function (val) {
31330 if (Array.isArray(val) || isObject$3(val)) {
31331 var tmpDepth = getTreeDepth(val);
31333 if (tmpDepth > depth) {
31344 function stringify(obj, options) {
31345 options = options || {};
31346 var indent = JSON.stringify([1], null, get(options, 'indent', 2)).slice(2, -3);
31347 var addMargin = get(options, 'margins', false);
31348 var addArrayMargin = get(options, 'arrayMargins', false);
31349 var addObjectMargin = get(options, 'objectMargins', false);
31350 var maxLength = indent === '' ? Infinity : get(options, 'maxLength', 80);
31351 var maxNesting = get(options, 'maxNesting', Infinity);
31352 return function _stringify(obj, currentIndent, reserved) {
31353 if (obj && typeof obj.toJSON === 'function') {
31354 obj = obj.toJSON();
31357 var string = JSON.stringify(obj);
31359 if (string === undefined) {
31363 var length = maxLength - currentIndent.length - reserved;
31364 var treeDepth = getTreeDepth(obj);
31366 if (treeDepth <= maxNesting && string.length <= length) {
31367 var prettified = prettify(string, {
31368 addMargin: addMargin,
31369 addArrayMargin: addArrayMargin,
31370 addObjectMargin: addObjectMargin
31373 if (prettified.length <= length) {
31378 if (isObject$3(obj)) {
31379 var nextIndent = currentIndent + indent;
31383 var comma = function comma(array, index) {
31384 return index === array.length - 1 ? 0 : 1;
31387 if (Array.isArray(obj)) {
31388 for (var index = 0; index < obj.length; index++) {
31389 items.push(_stringify(obj[index], nextIndent, comma(obj, index)) || 'null');
31394 Object.keys(obj).forEach(function (key, index, array) {
31395 var keyPart = JSON.stringify(key) + ': ';
31397 var value = _stringify(obj[key], nextIndent, keyPart.length + comma(array, index));
31399 if (value !== undefined) {
31400 items.push(keyPart + value);
31406 if (items.length > 0) {
31407 return [delimiters[0], indent + items.join(',\n' + nextIndent), delimiters[1]].join('\n' + currentIndent);
31413 } // Note: This regex matches even invalid JSON strings, but since we’re
31414 // working on the output of `JSON.stringify` we know that only valid strings
31415 // are present (unless the user supplied a weird `options.indent` but in
31416 // that case we don’t care since the output would be invalid anyway).
31419 var stringOrChar = /("(?:[^\\"]|\\.)*")|[:,\][}{]/g;
31421 function prettify(string, options) {
31422 options = options || {};
31432 if (options.addMargin || options.addObjectMargin) {
31433 tokens['{'] = '{ ';
31434 tokens['}'] = ' }';
31437 if (options.addMargin || options.addArrayMargin) {
31438 tokens['['] = '[ ';
31439 tokens[']'] = ' ]';
31442 return string.replace(stringOrChar, function (match, string) {
31443 return string ? match : tokens[match];
31447 function get(options, name, defaultValue) {
31448 return name in options ? options[name] : defaultValue;
31451 var jsonStringifyPrettyCompact = stringify;
31453 var _default = /*#__PURE__*/function () {
31456 // `fc` Optional FeatureCollection of known features
31458 // Optionally pass a GeoJSON FeatureCollection of known features which we can refer to later.
31459 // Each feature must have a filename-like `id`, for example: `something.geojson`
31462 // "type": "FeatureCollection"
31465 // "type": "Feature",
31466 // "id": "philly_metro.geojson",
31467 // "properties": { … },
31468 // "geometry": { … }
31472 function _default(fc) {
31475 _classCallCheck$1(this, _default);
31477 // The _cache retains resolved features, so if you ask for the same thing multiple times
31478 // we don't repeat the expensive resolving/clipping operations.
31480 // Each feature has a stable identifier that is used as the cache key.
31481 // The identifiers look like:
31482 // - for point locations, the stringified point: e.g. '[8.67039,49.41882]'
31483 // - for geojson locations, the geojson id: e.g. 'de-hamburg.geojson'
31484 // - for countrycoder locations, feature.id property: e.g. 'Q2' (countrycoder uses Wikidata identifiers)
31485 // - for aggregated locationSets, +[include]-[exclude]: e.g '+[Q2]-[Q18,Q27611]'
31486 this._cache = {}; // When strict mode = true, throw on invalid locations or locationSets.
31487 // When strict mode = false, return `null` for invalid locations or locationSets.
31489 this._strict = true; // process input FeatureCollection
31491 if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
31492 fc.features.forEach(function (feature) {
31493 feature.properties = feature.properties || {};
31494 var props = feature.properties; // Get `id` from either `id` or `properties`
31496 var id = feature.id || props.id;
31497 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
31499 id = id.toLowerCase();
31501 props.id = id; // Ensure `area` property exists
31504 var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
31506 props.area = Number(area.toFixed(2));
31509 _this._cache[id] = feature;
31511 } // Replace CountryCoder world geometry to be a polygon covering the world.
31514 var world = _cloneDeep(feature$1('Q2'));
31518 coordinates: [[[-180, -90], [180, -90], [180, 90], [-180, 90], [-180, -90]]]
31521 world.properties.id = 'Q2';
31522 world.properties.area = geojsonArea.geometry(world.geometry) / 1e6; // m² to km²
31524 this._cache.Q2 = world;
31525 } // validateLocation
31526 // `location` The location to validate
31528 // Pass a `location` value to validate
31530 // Returns a result like:
31532 // type: 'point', 'geojson', or 'countrycoder'
31533 // location: the queried location
31534 // id: the stable identifier for the feature
31536 // or `null` if the location is invalid
31540 _createClass$1(_default, [{
31541 key: "validateLocation",
31542 value: function validateLocation(location) {
31543 if (Array.isArray(location) && (location.length === 2 || location.length === 3)) {
31544 // [lon, lat] or [lon, lat, radius] point?
31545 var lon = location[0];
31546 var lat = location[1];
31547 var radius = location[2];
31549 if (Number.isFinite(lon) && lon >= -180 && lon <= 180 && Number.isFinite(lat) && lat >= -90 && lat <= 90 && (location.length === 2 || Number.isFinite(radius) && radius > 0)) {
31550 var id = '[' + location.toString() + ']';
31553 location: location,
31557 } else if (typeof location === 'string' && /^\S+\.geojson$/i.test(location)) {
31558 // a .geojson filename?
31559 var _id = location.toLowerCase();
31561 if (this._cache[_id]) {
31564 location: location,
31568 } else if (typeof location === 'string' || typeof location === 'number') {
31569 // a country-coder value?
31570 var feature = feature$1(location);
31573 // Use wikidata QID as the identifier, since that seems to be the one
31574 // property that everything in CountryCoder is guaranteed to have.
31575 var _id2 = feature.properties.wikidata;
31577 type: 'countrycoder',
31578 location: location,
31584 if (this._strict) {
31585 throw new Error("validateLocation: Invalid location: \"".concat(location, "\"."));
31589 } // resolveLocation
31590 // `location` The location to resolve
31592 // Pass a `location` value to resolve
31594 // Returns a result like:
31596 // type: 'point', 'geojson', or 'countrycoder'
31597 // location: the queried location
31598 // id: a stable identifier for the feature
31599 // feature: the resolved GeoJSON feature
31601 // or `null` if the location is invalid
31605 key: "resolveLocation",
31606 value: function resolveLocation(location) {
31607 var valid = this.validateLocation(location);
31608 if (!valid) return null;
31609 var id = valid.id; // Return a result from cache if we can
31611 if (this._cache[id]) {
31612 return Object.assign(valid, {
31613 feature: this._cache[id]
31615 } // A [lon,lat] coordinate pair?
31618 if (valid.type === 'point') {
31619 var lon = location[0];
31620 var lat = location[1];
31621 var radius = location[2] || 25; // km
31625 var area = Math.PI * radius * radius;
31626 var feature = this._cache[id] = precision({
31631 area: Number(area.toFixed(2))
31633 geometry: circleToPolygon([lon, lat], radius * 1000, EDGES) // km to m
31636 return Object.assign(valid, {
31638 }); // A .geojson filename?
31639 } else if (valid.type === 'geojson') ; else if (valid.type === 'countrycoder') {
31640 var _feature = _cloneDeep(feature$1(id));
31642 var props = _feature.properties; // -> This block of code is weird and requires some explanation. <-
31643 // CountryCoder includes higher level features which are made up of members.
31644 // These features don't have their own geometry, but CountryCoder provides an
31645 // `aggregateFeature` method to combine these members into a MultiPolygon.
31646 // In the past, Turf/JSTS/martinez could not handle the aggregated features,
31647 // so we'd iteratively union them all together. (this was slow)
31648 // But now mfogel/polygon-clipping handles these MultiPolygons like a boss.
31649 // This approach also has the benefit of removing all the internal boaders and
31650 // simplifying the regional polygons a lot.
31652 if (Array.isArray(props.members)) {
31653 var aggregate = aggregateFeature(id);
31654 aggregate.geometry.coordinates = _clip([aggregate], 'UNION').geometry.coordinates;
31655 _feature.geometry = aggregate.geometry;
31656 } // Ensure `area` property exists
31660 var _area = geojsonArea.geometry(_feature.geometry) / 1e6; // m² to km²
31663 props.area = Number(_area.toFixed(2));
31664 } // Ensure `id` property exists
31669 this._cache[id] = _feature;
31670 return Object.assign(valid, {
31675 if (this._strict) {
31676 throw new Error("resolveLocation: Couldn't resolve location \"".concat(location, "\"."));
31680 } // validateLocationSet
31681 // `locationSet` the locationSet to validate
31683 // Pass a locationSet Object to validate like:
31685 // include: [ Array of locations ],
31686 // exclude: [ Array of locations ]
31689 // Returns a result like:
31691 // type: 'locationset'
31692 // locationSet: the queried locationSet
31693 // id: the stable identifier for the feature
31695 // or `null` if the locationSet is invalid
31699 key: "validateLocationSet",
31700 value: function validateLocationSet(locationSet) {
31701 locationSet = locationSet || {};
31702 var validator = this.validateLocation.bind(this);
31703 var include = (locationSet.include || []).map(validator).filter(Boolean);
31704 var exclude = (locationSet.exclude || []).map(validator).filter(Boolean);
31706 if (!include.length) {
31707 if (this._strict) {
31708 throw new Error("validateLocationSet: LocationSet includes nothing.");
31710 // non-strict mode, replace an empty locationSet with one that includes "the world"
31711 locationSet.include = ['Q2'];
31713 type: 'countrycoder',
31718 } // Generate stable identifier
31721 include.sort(_sortLocations);
31722 var id = '+[' + include.map(function (d) {
31724 }).join(',') + ']';
31726 if (exclude.length) {
31727 exclude.sort(_sortLocations);
31728 id += '-[' + exclude.map(function (d) {
31730 }).join(',') + ']';
31734 type: 'locationset',
31735 locationSet: locationSet,
31738 } // resolveLocationSet
31739 // `locationSet` the locationSet to resolve
31741 // Pass a locationSet Object to validate like:
31743 // include: [ Array of locations ],
31744 // exclude: [ Array of locations ]
31747 // Returns a result like:
31749 // type: 'locationset'
31750 // locationSet: the queried locationSet
31751 // id: the stable identifier for the feature
31752 // feature: the resolved GeoJSON feature
31754 // or `null` if the locationSet is invalid
31758 key: "resolveLocationSet",
31759 value: function resolveLocationSet(locationSet) {
31760 locationSet = locationSet || {};
31761 var valid = this.validateLocationSet(locationSet);
31762 if (!valid) return null;
31763 var id = valid.id; // Return a result from cache if we can
31765 if (this._cache[id]) {
31766 return Object.assign(valid, {
31767 feature: this._cache[id]
31771 var resolver = this.resolveLocation.bind(this);
31772 var includes = (locationSet.include || []).map(resolver).filter(Boolean);
31773 var excludes = (locationSet.exclude || []).map(resolver).filter(Boolean); // Return quickly if it's a single included location..
31775 if (includes.length === 1 && excludes.length === 0) {
31776 return Object.assign(valid, {
31777 feature: includes[0].feature
31779 } // Calculate unions
31782 var includeGeoJSON = _clip(includes.map(function (d) {
31786 var excludeGeoJSON = _clip(excludes.map(function (d) {
31788 }), 'UNION'); // Calculate difference, update `area` and return result
31791 var resultGeoJSON = excludeGeoJSON ? _clip([includeGeoJSON, excludeGeoJSON], 'DIFFERENCE') : includeGeoJSON;
31792 var area = geojsonArea.geometry(resultGeoJSON.geometry) / 1e6; // m² to km²
31794 resultGeoJSON.id = id;
31795 resultGeoJSON.properties = {
31797 area: Number(area.toFixed(2))
31799 this._cache[id] = resultGeoJSON;
31800 return Object.assign(valid, {
31801 feature: resultGeoJSON
31808 value: function strict(val) {
31809 if (val === undefined) {
31811 return this._strict;
31814 this._strict = val;
31818 // convenience method to access the internal cache
31822 value: function cache() {
31823 return this._cache;
31825 // convenience method to prettyStringify the given object
31829 value: function stringify(obj, options) {
31830 return jsonStringifyPrettyCompact(obj, options);
31835 }(); // Wrap the mfogel/polygon-clipping library and return a GeoJSON feature.
31837 function _clip(features, which) {
31838 if (!Array.isArray(features) || !features.length) return null;
31840 UNION: index.union,
31841 DIFFERENCE: index.difference
31843 var args = features.map(function (feature) {
31844 return feature.geometry.coordinates;
31846 var coords = fn.apply(null, args);
31851 type: whichType(coords),
31852 coordinates: coords
31854 }; // is this a Polygon or a MultiPolygon?
31856 function whichType(coords) {
31857 var a = Array.isArray(coords);
31858 var b = a && Array.isArray(coords[0]);
31859 var c = b && Array.isArray(coords[0][0]);
31860 var d = c && Array.isArray(coords[0][0][0]);
31861 return d ? 'MultiPolygon' : 'Polygon';
31865 function _cloneDeep(obj) {
31866 return JSON.parse(JSON.stringify(obj));
31867 } // Sorting the location lists is ok because they end up unioned together.
31868 // This sorting makes it possible to generate a deterministic id.
31871 function _sortLocations(a, b) {
31877 var aRank = rank[a.type];
31878 var bRank = rank[b.type];
31879 return aRank > bRank ? 1 : aRank < bRank ? -1 : a.id.localeCompare(b.id);
31884 // `Number.MAX_SAFE_INTEGER` constant
31885 // https://tc39.es/ecma262/#sec-number.max_safe_integer
31886 $$b({ target: 'Number', stat: true }, {
31887 MAX_SAFE_INTEGER: 0x1FFFFFFFFFFFFF
31890 var aesJs = {exports: {}};
31892 (function (module, exports) {
31895 function checkInt(value) {
31896 return parseInt(value) === value;
31899 function checkInts(arrayish) {
31900 if (!checkInt(arrayish.length)) {
31904 for (var i = 0; i < arrayish.length; i++) {
31905 if (!checkInt(arrayish[i]) || arrayish[i] < 0 || arrayish[i] > 255) {
31913 function coerceArray(arg, copy) {
31914 // ArrayBuffer view
31915 if (arg.buffer && arg.name === 'Uint8Array') {
31920 arg = Array.prototype.slice.call(arg);
31925 } // It's an array; check it is a valid representation of a byte
31928 if (Array.isArray(arg)) {
31929 if (!checkInts(arg)) {
31930 throw new Error('Array contains invalid value: ' + arg);
31933 return new Uint8Array(arg);
31934 } // Something else, but behaves like an array (maybe a Buffer? Arguments?)
31937 if (checkInt(arg.length) && checkInts(arg)) {
31938 return new Uint8Array(arg);
31941 throw new Error('unsupported array-like object');
31944 function createArray(length) {
31945 return new Uint8Array(length);
31948 function copyArray(sourceArray, targetArray, targetStart, sourceStart, sourceEnd) {
31949 if (sourceStart != null || sourceEnd != null) {
31950 if (sourceArray.slice) {
31951 sourceArray = sourceArray.slice(sourceStart, sourceEnd);
31953 sourceArray = Array.prototype.slice.call(sourceArray, sourceStart, sourceEnd);
31957 targetArray.set(sourceArray, targetStart);
31960 var convertUtf8 = function () {
31961 function toBytes(text) {
31964 text = encodeURI(text);
31966 while (i < text.length) {
31967 var c = text.charCodeAt(i++); // if it is a % sign, encode the following 2 bytes as a hex value
31970 result.push(parseInt(text.substr(i, 2), 16));
31971 i += 2; // otherwise, just the actual byte
31977 return coerceArray(result);
31980 function fromBytes(bytes) {
31984 while (i < bytes.length) {
31988 result.push(String.fromCharCode(c));
31990 } else if (c > 191 && c < 224) {
31991 result.push(String.fromCharCode((c & 0x1f) << 6 | bytes[i + 1] & 0x3f));
31994 result.push(String.fromCharCode((c & 0x0f) << 12 | (bytes[i + 1] & 0x3f) << 6 | bytes[i + 2] & 0x3f));
31999 return result.join('');
32004 fromBytes: fromBytes
32008 var convertHex = function () {
32009 function toBytes(text) {
32012 for (var i = 0; i < text.length; i += 2) {
32013 result.push(parseInt(text.substr(i, 2), 16));
32017 } // http://ixti.net/development/javascript/2011/11/11/base64-encodedecode-of-utf8-in-browser-with-js.html
32020 var Hex = '0123456789abcdef';
32022 function fromBytes(bytes) {
32025 for (var i = 0; i < bytes.length; i++) {
32027 result.push(Hex[(v & 0xf0) >> 4] + Hex[v & 0x0f]);
32030 return result.join('');
32035 fromBytes: fromBytes
32037 }(); // Number of rounds by keysize
32040 var numberOfRounds = {
32044 }; // Round constant words
32046 var rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91]; // S-box and Inverse S-box (S is for Substitution)
32048 var S = [0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16];
32049 var Si = [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d]; // Transformations for encryption
32051 var T1 = [0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a];
32052 var T2 = [0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5, 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676, 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0, 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0, 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc, 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515, 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a, 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575, 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0, 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484, 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b, 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf, 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585, 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8, 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5, 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2, 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717, 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373, 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888, 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb, 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c, 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979, 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9, 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808, 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6, 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a, 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e, 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e, 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494, 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf, 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868, 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616];
32053 var T3 = [0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5, 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76, 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0, 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0, 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc, 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15, 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a, 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75, 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0, 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384, 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b, 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf, 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185, 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8, 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5, 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2, 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17, 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673, 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88, 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb, 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c, 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279, 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9, 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008, 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6, 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a, 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e, 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e, 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394, 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df, 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068, 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16];
32054 var T4 = [0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491, 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec, 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb, 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b, 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83, 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a, 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f, 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea, 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b, 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713, 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6, 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85, 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411, 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b, 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1, 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf, 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e, 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6, 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b, 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad, 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8, 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2, 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049, 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810, 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197, 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f, 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c, 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927, 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733, 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5, 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0, 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c]; // Transformations for decryption
32056 var T5 = [0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742];
32057 var T6 = [0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303, 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3, 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9, 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8, 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a, 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b, 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab, 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682, 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe, 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10, 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015, 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee, 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72, 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e, 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a, 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9, 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e, 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611, 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3, 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390, 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf, 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af, 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb, 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8, 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266, 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6, 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551, 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647, 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1, 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db, 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95, 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857];
32058 var T7 = [0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3, 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562, 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3, 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9, 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce, 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908, 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655, 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16, 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6, 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e, 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050, 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8, 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a, 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436, 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12, 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e, 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb, 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6, 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1, 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233, 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad, 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3, 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b, 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15, 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2, 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791, 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665, 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6, 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47, 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844, 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d, 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8];
32059 var T8 = [0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b, 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5, 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b, 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e, 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d, 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9, 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66, 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced, 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4, 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd, 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60, 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79, 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c, 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24, 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c, 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814, 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b, 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084, 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077, 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22, 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f, 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582, 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb, 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef, 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035, 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17, 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46, 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d, 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a, 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678, 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff, 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0]; // Transformations for decryption key expansion
32061 var U1 = [0x00000000, 0x0e090d0b, 0x1c121a16, 0x121b171d, 0x3824342c, 0x362d3927, 0x24362e3a, 0x2a3f2331, 0x70486858, 0x7e416553, 0x6c5a724e, 0x62537f45, 0x486c5c74, 0x4665517f, 0x547e4662, 0x5a774b69, 0xe090d0b0, 0xee99ddbb, 0xfc82caa6, 0xf28bc7ad, 0xd8b4e49c, 0xd6bde997, 0xc4a6fe8a, 0xcaaff381, 0x90d8b8e8, 0x9ed1b5e3, 0x8ccaa2fe, 0x82c3aff5, 0xa8fc8cc4, 0xa6f581cf, 0xb4ee96d2, 0xbae79bd9, 0xdb3bbb7b, 0xd532b670, 0xc729a16d, 0xc920ac66, 0xe31f8f57, 0xed16825c, 0xff0d9541, 0xf104984a, 0xab73d323, 0xa57ade28, 0xb761c935, 0xb968c43e, 0x9357e70f, 0x9d5eea04, 0x8f45fd19, 0x814cf012, 0x3bab6bcb, 0x35a266c0, 0x27b971dd, 0x29b07cd6, 0x038f5fe7, 0x0d8652ec, 0x1f9d45f1, 0x119448fa, 0x4be30393, 0x45ea0e98, 0x57f11985, 0x59f8148e, 0x73c737bf, 0x7dce3ab4, 0x6fd52da9, 0x61dc20a2, 0xad766df6, 0xa37f60fd, 0xb16477e0, 0xbf6d7aeb, 0x955259da, 0x9b5b54d1, 0x894043cc, 0x87494ec7, 0xdd3e05ae, 0xd33708a5, 0xc12c1fb8, 0xcf2512b3, 0xe51a3182, 0xeb133c89, 0xf9082b94, 0xf701269f, 0x4de6bd46, 0x43efb04d, 0x51f4a750, 0x5ffdaa5b, 0x75c2896a, 0x7bcb8461, 0x69d0937c, 0x67d99e77, 0x3daed51e, 0x33a7d815, 0x21bccf08, 0x2fb5c203, 0x058ae132, 0x0b83ec39, 0x1998fb24, 0x1791f62f, 0x764dd68d, 0x7844db86, 0x6a5fcc9b, 0x6456c190, 0x4e69e2a1, 0x4060efaa, 0x527bf8b7, 0x5c72f5bc, 0x0605bed5, 0x080cb3de, 0x1a17a4c3, 0x141ea9c8, 0x3e218af9, 0x302887f2, 0x223390ef, 0x2c3a9de4, 0x96dd063d, 0x98d40b36, 0x8acf1c2b, 0x84c61120, 0xaef93211, 0xa0f03f1a, 0xb2eb2807, 0xbce2250c, 0xe6956e65, 0xe89c636e, 0xfa877473, 0xf48e7978, 0xdeb15a49, 0xd0b85742, 0xc2a3405f, 0xccaa4d54, 0x41ecdaf7, 0x4fe5d7fc, 0x5dfec0e1, 0x53f7cdea, 0x79c8eedb, 0x77c1e3d0, 0x65daf4cd, 0x6bd3f9c6, 0x31a4b2af, 0x3fadbfa4, 0x2db6a8b9, 0x23bfa5b2, 0x09808683, 0x07898b88, 0x15929c95, 0x1b9b919e, 0xa17c0a47, 0xaf75074c, 0xbd6e1051, 0xb3671d5a, 0x99583e6b, 0x97513360, 0x854a247d, 0x8b432976, 0xd134621f, 0xdf3d6f14, 0xcd267809, 0xc32f7502, 0xe9105633, 0xe7195b38, 0xf5024c25, 0xfb0b412e, 0x9ad7618c, 0x94de6c87, 0x86c57b9a, 0x88cc7691, 0xa2f355a0, 0xacfa58ab, 0xbee14fb6, 0xb0e842bd, 0xea9f09d4, 0xe49604df, 0xf68d13c2, 0xf8841ec9, 0xd2bb3df8, 0xdcb230f3, 0xcea927ee, 0xc0a02ae5, 0x7a47b13c, 0x744ebc37, 0x6655ab2a, 0x685ca621, 0x42638510, 0x4c6a881b, 0x5e719f06, 0x5078920d, 0x0a0fd964, 0x0406d46f, 0x161dc372, 0x1814ce79, 0x322bed48, 0x3c22e043, 0x2e39f75e, 0x2030fa55, 0xec9ab701, 0xe293ba0a, 0xf088ad17, 0xfe81a01c, 0xd4be832d, 0xdab78e26, 0xc8ac993b, 0xc6a59430, 0x9cd2df59, 0x92dbd252, 0x80c0c54f, 0x8ec9c844, 0xa4f6eb75, 0xaaffe67e, 0xb8e4f163, 0xb6edfc68, 0x0c0a67b1, 0x02036aba, 0x10187da7, 0x1e1170ac, 0x342e539d, 0x3a275e96, 0x283c498b, 0x26354480, 0x7c420fe9, 0x724b02e2, 0x605015ff, 0x6e5918f4, 0x44663bc5, 0x4a6f36ce, 0x587421d3, 0x567d2cd8, 0x37a10c7a, 0x39a80171, 0x2bb3166c, 0x25ba1b67, 0x0f853856, 0x018c355d, 0x13972240, 0x1d9e2f4b, 0x47e96422, 0x49e06929, 0x5bfb7e34, 0x55f2733f, 0x7fcd500e, 0x71c45d05, 0x63df4a18, 0x6dd64713, 0xd731dcca, 0xd938d1c1, 0xcb23c6dc, 0xc52acbd7, 0xef15e8e6, 0xe11ce5ed, 0xf307f2f0, 0xfd0efffb, 0xa779b492, 0xa970b999, 0xbb6bae84, 0xb562a38f, 0x9f5d80be, 0x91548db5, 0x834f9aa8, 0x8d4697a3];
32062 var U2 = [0x00000000, 0x0b0e090d, 0x161c121a, 0x1d121b17, 0x2c382434, 0x27362d39, 0x3a24362e, 0x312a3f23, 0x58704868, 0x537e4165, 0x4e6c5a72, 0x4562537f, 0x74486c5c, 0x7f466551, 0x62547e46, 0x695a774b, 0xb0e090d0, 0xbbee99dd, 0xa6fc82ca, 0xadf28bc7, 0x9cd8b4e4, 0x97d6bde9, 0x8ac4a6fe, 0x81caaff3, 0xe890d8b8, 0xe39ed1b5, 0xfe8ccaa2, 0xf582c3af, 0xc4a8fc8c, 0xcfa6f581, 0xd2b4ee96, 0xd9bae79b, 0x7bdb3bbb, 0x70d532b6, 0x6dc729a1, 0x66c920ac, 0x57e31f8f, 0x5ced1682, 0x41ff0d95, 0x4af10498, 0x23ab73d3, 0x28a57ade, 0x35b761c9, 0x3eb968c4, 0x0f9357e7, 0x049d5eea, 0x198f45fd, 0x12814cf0, 0xcb3bab6b, 0xc035a266, 0xdd27b971, 0xd629b07c, 0xe7038f5f, 0xec0d8652, 0xf11f9d45, 0xfa119448, 0x934be303, 0x9845ea0e, 0x8557f119, 0x8e59f814, 0xbf73c737, 0xb47dce3a, 0xa96fd52d, 0xa261dc20, 0xf6ad766d, 0xfda37f60, 0xe0b16477, 0xebbf6d7a, 0xda955259, 0xd19b5b54, 0xcc894043, 0xc787494e, 0xaedd3e05, 0xa5d33708, 0xb8c12c1f, 0xb3cf2512, 0x82e51a31, 0x89eb133c, 0x94f9082b, 0x9ff70126, 0x464de6bd, 0x4d43efb0, 0x5051f4a7, 0x5b5ffdaa, 0x6a75c289, 0x617bcb84, 0x7c69d093, 0x7767d99e, 0x1e3daed5, 0x1533a7d8, 0x0821bccf, 0x032fb5c2, 0x32058ae1, 0x390b83ec, 0x241998fb, 0x2f1791f6, 0x8d764dd6, 0x867844db, 0x9b6a5fcc, 0x906456c1, 0xa14e69e2, 0xaa4060ef, 0xb7527bf8, 0xbc5c72f5, 0xd50605be, 0xde080cb3, 0xc31a17a4, 0xc8141ea9, 0xf93e218a, 0xf2302887, 0xef223390, 0xe42c3a9d, 0x3d96dd06, 0x3698d40b, 0x2b8acf1c, 0x2084c611, 0x11aef932, 0x1aa0f03f, 0x07b2eb28, 0x0cbce225, 0x65e6956e, 0x6ee89c63, 0x73fa8774, 0x78f48e79, 0x49deb15a, 0x42d0b857, 0x5fc2a340, 0x54ccaa4d, 0xf741ecda, 0xfc4fe5d7, 0xe15dfec0, 0xea53f7cd, 0xdb79c8ee, 0xd077c1e3, 0xcd65daf4, 0xc66bd3f9, 0xaf31a4b2, 0xa43fadbf, 0xb92db6a8, 0xb223bfa5, 0x83098086, 0x8807898b, 0x9515929c, 0x9e1b9b91, 0x47a17c0a, 0x4caf7507, 0x51bd6e10, 0x5ab3671d, 0x6b99583e, 0x60975133, 0x7d854a24, 0x768b4329, 0x1fd13462, 0x14df3d6f, 0x09cd2678, 0x02c32f75, 0x33e91056, 0x38e7195b, 0x25f5024c, 0x2efb0b41, 0x8c9ad761, 0x8794de6c, 0x9a86c57b, 0x9188cc76, 0xa0a2f355, 0xabacfa58, 0xb6bee14f, 0xbdb0e842, 0xd4ea9f09, 0xdfe49604, 0xc2f68d13, 0xc9f8841e, 0xf8d2bb3d, 0xf3dcb230, 0xeecea927, 0xe5c0a02a, 0x3c7a47b1, 0x37744ebc, 0x2a6655ab, 0x21685ca6, 0x10426385, 0x1b4c6a88, 0x065e719f, 0x0d507892, 0x640a0fd9, 0x6f0406d4, 0x72161dc3, 0x791814ce, 0x48322bed, 0x433c22e0, 0x5e2e39f7, 0x552030fa, 0x01ec9ab7, 0x0ae293ba, 0x17f088ad, 0x1cfe81a0, 0x2dd4be83, 0x26dab78e, 0x3bc8ac99, 0x30c6a594, 0x599cd2df, 0x5292dbd2, 0x4f80c0c5, 0x448ec9c8, 0x75a4f6eb, 0x7eaaffe6, 0x63b8e4f1, 0x68b6edfc, 0xb10c0a67, 0xba02036a, 0xa710187d, 0xac1e1170, 0x9d342e53, 0x963a275e, 0x8b283c49, 0x80263544, 0xe97c420f, 0xe2724b02, 0xff605015, 0xf46e5918, 0xc544663b, 0xce4a6f36, 0xd3587421, 0xd8567d2c, 0x7a37a10c, 0x7139a801, 0x6c2bb316, 0x6725ba1b, 0x560f8538, 0x5d018c35, 0x40139722, 0x4b1d9e2f, 0x2247e964, 0x2949e069, 0x345bfb7e, 0x3f55f273, 0x0e7fcd50, 0x0571c45d, 0x1863df4a, 0x136dd647, 0xcad731dc, 0xc1d938d1, 0xdccb23c6, 0xd7c52acb, 0xe6ef15e8, 0xede11ce5, 0xf0f307f2, 0xfbfd0eff, 0x92a779b4, 0x99a970b9, 0x84bb6bae, 0x8fb562a3, 0xbe9f5d80, 0xb591548d, 0xa8834f9a, 0xa38d4697];
32063 var U3 = [0x00000000, 0x0d0b0e09, 0x1a161c12, 0x171d121b, 0x342c3824, 0x3927362d, 0x2e3a2436, 0x23312a3f, 0x68587048, 0x65537e41, 0x724e6c5a, 0x7f456253, 0x5c74486c, 0x517f4665, 0x4662547e, 0x4b695a77, 0xd0b0e090, 0xddbbee99, 0xcaa6fc82, 0xc7adf28b, 0xe49cd8b4, 0xe997d6bd, 0xfe8ac4a6, 0xf381caaf, 0xb8e890d8, 0xb5e39ed1, 0xa2fe8cca, 0xaff582c3, 0x8cc4a8fc, 0x81cfa6f5, 0x96d2b4ee, 0x9bd9bae7, 0xbb7bdb3b, 0xb670d532, 0xa16dc729, 0xac66c920, 0x8f57e31f, 0x825ced16, 0x9541ff0d, 0x984af104, 0xd323ab73, 0xde28a57a, 0xc935b761, 0xc43eb968, 0xe70f9357, 0xea049d5e, 0xfd198f45, 0xf012814c, 0x6bcb3bab, 0x66c035a2, 0x71dd27b9, 0x7cd629b0, 0x5fe7038f, 0x52ec0d86, 0x45f11f9d, 0x48fa1194, 0x03934be3, 0x0e9845ea, 0x198557f1, 0x148e59f8, 0x37bf73c7, 0x3ab47dce, 0x2da96fd5, 0x20a261dc, 0x6df6ad76, 0x60fda37f, 0x77e0b164, 0x7aebbf6d, 0x59da9552, 0x54d19b5b, 0x43cc8940, 0x4ec78749, 0x05aedd3e, 0x08a5d337, 0x1fb8c12c, 0x12b3cf25, 0x3182e51a, 0x3c89eb13, 0x2b94f908, 0x269ff701, 0xbd464de6, 0xb04d43ef, 0xa75051f4, 0xaa5b5ffd, 0x896a75c2, 0x84617bcb, 0x937c69d0, 0x9e7767d9, 0xd51e3dae, 0xd81533a7, 0xcf0821bc, 0xc2032fb5, 0xe132058a, 0xec390b83, 0xfb241998, 0xf62f1791, 0xd68d764d, 0xdb867844, 0xcc9b6a5f, 0xc1906456, 0xe2a14e69, 0xefaa4060, 0xf8b7527b, 0xf5bc5c72, 0xbed50605, 0xb3de080c, 0xa4c31a17, 0xa9c8141e, 0x8af93e21, 0x87f23028, 0x90ef2233, 0x9de42c3a, 0x063d96dd, 0x0b3698d4, 0x1c2b8acf, 0x112084c6, 0x3211aef9, 0x3f1aa0f0, 0x2807b2eb, 0x250cbce2, 0x6e65e695, 0x636ee89c, 0x7473fa87, 0x7978f48e, 0x5a49deb1, 0x5742d0b8, 0x405fc2a3, 0x4d54ccaa, 0xdaf741ec, 0xd7fc4fe5, 0xc0e15dfe, 0xcdea53f7, 0xeedb79c8, 0xe3d077c1, 0xf4cd65da, 0xf9c66bd3, 0xb2af31a4, 0xbfa43fad, 0xa8b92db6, 0xa5b223bf, 0x86830980, 0x8b880789, 0x9c951592, 0x919e1b9b, 0x0a47a17c, 0x074caf75, 0x1051bd6e, 0x1d5ab367, 0x3e6b9958, 0x33609751, 0x247d854a, 0x29768b43, 0x621fd134, 0x6f14df3d, 0x7809cd26, 0x7502c32f, 0x5633e910, 0x5b38e719, 0x4c25f502, 0x412efb0b, 0x618c9ad7, 0x6c8794de, 0x7b9a86c5, 0x769188cc, 0x55a0a2f3, 0x58abacfa, 0x4fb6bee1, 0x42bdb0e8, 0x09d4ea9f, 0x04dfe496, 0x13c2f68d, 0x1ec9f884, 0x3df8d2bb, 0x30f3dcb2, 0x27eecea9, 0x2ae5c0a0, 0xb13c7a47, 0xbc37744e, 0xab2a6655, 0xa621685c, 0x85104263, 0x881b4c6a, 0x9f065e71, 0x920d5078, 0xd9640a0f, 0xd46f0406, 0xc372161d, 0xce791814, 0xed48322b, 0xe0433c22, 0xf75e2e39, 0xfa552030, 0xb701ec9a, 0xba0ae293, 0xad17f088, 0xa01cfe81, 0x832dd4be, 0x8e26dab7, 0x993bc8ac, 0x9430c6a5, 0xdf599cd2, 0xd25292db, 0xc54f80c0, 0xc8448ec9, 0xeb75a4f6, 0xe67eaaff, 0xf163b8e4, 0xfc68b6ed, 0x67b10c0a, 0x6aba0203, 0x7da71018, 0x70ac1e11, 0x539d342e, 0x5e963a27, 0x498b283c, 0x44802635, 0x0fe97c42, 0x02e2724b, 0x15ff6050, 0x18f46e59, 0x3bc54466, 0x36ce4a6f, 0x21d35874, 0x2cd8567d, 0x0c7a37a1, 0x017139a8, 0x166c2bb3, 0x1b6725ba, 0x38560f85, 0x355d018c, 0x22401397, 0x2f4b1d9e, 0x642247e9, 0x692949e0, 0x7e345bfb, 0x733f55f2, 0x500e7fcd, 0x5d0571c4, 0x4a1863df, 0x47136dd6, 0xdccad731, 0xd1c1d938, 0xc6dccb23, 0xcbd7c52a, 0xe8e6ef15, 0xe5ede11c, 0xf2f0f307, 0xfffbfd0e, 0xb492a779, 0xb999a970, 0xae84bb6b, 0xa38fb562, 0x80be9f5d, 0x8db59154, 0x9aa8834f, 0x97a38d46];
32064 var U4 = [0x00000000, 0x090d0b0e, 0x121a161c, 0x1b171d12, 0x24342c38, 0x2d392736, 0x362e3a24, 0x3f23312a, 0x48685870, 0x4165537e, 0x5a724e6c, 0x537f4562, 0x6c5c7448, 0x65517f46, 0x7e466254, 0x774b695a, 0x90d0b0e0, 0x99ddbbee, 0x82caa6fc, 0x8bc7adf2, 0xb4e49cd8, 0xbde997d6, 0xa6fe8ac4, 0xaff381ca, 0xd8b8e890, 0xd1b5e39e, 0xcaa2fe8c, 0xc3aff582, 0xfc8cc4a8, 0xf581cfa6, 0xee96d2b4, 0xe79bd9ba, 0x3bbb7bdb, 0x32b670d5, 0x29a16dc7, 0x20ac66c9, 0x1f8f57e3, 0x16825ced, 0x0d9541ff, 0x04984af1, 0x73d323ab, 0x7ade28a5, 0x61c935b7, 0x68c43eb9, 0x57e70f93, 0x5eea049d, 0x45fd198f, 0x4cf01281, 0xab6bcb3b, 0xa266c035, 0xb971dd27, 0xb07cd629, 0x8f5fe703, 0x8652ec0d, 0x9d45f11f, 0x9448fa11, 0xe303934b, 0xea0e9845, 0xf1198557, 0xf8148e59, 0xc737bf73, 0xce3ab47d, 0xd52da96f, 0xdc20a261, 0x766df6ad, 0x7f60fda3, 0x6477e0b1, 0x6d7aebbf, 0x5259da95, 0x5b54d19b, 0x4043cc89, 0x494ec787, 0x3e05aedd, 0x3708a5d3, 0x2c1fb8c1, 0x2512b3cf, 0x1a3182e5, 0x133c89eb, 0x082b94f9, 0x01269ff7, 0xe6bd464d, 0xefb04d43, 0xf4a75051, 0xfdaa5b5f, 0xc2896a75, 0xcb84617b, 0xd0937c69, 0xd99e7767, 0xaed51e3d, 0xa7d81533, 0xbccf0821, 0xb5c2032f, 0x8ae13205, 0x83ec390b, 0x98fb2419, 0x91f62f17, 0x4dd68d76, 0x44db8678, 0x5fcc9b6a, 0x56c19064, 0x69e2a14e, 0x60efaa40, 0x7bf8b752, 0x72f5bc5c, 0x05bed506, 0x0cb3de08, 0x17a4c31a, 0x1ea9c814, 0x218af93e, 0x2887f230, 0x3390ef22, 0x3a9de42c, 0xdd063d96, 0xd40b3698, 0xcf1c2b8a, 0xc6112084, 0xf93211ae, 0xf03f1aa0, 0xeb2807b2, 0xe2250cbc, 0x956e65e6, 0x9c636ee8, 0x877473fa, 0x8e7978f4, 0xb15a49de, 0xb85742d0, 0xa3405fc2, 0xaa4d54cc, 0xecdaf741, 0xe5d7fc4f, 0xfec0e15d, 0xf7cdea53, 0xc8eedb79, 0xc1e3d077, 0xdaf4cd65, 0xd3f9c66b, 0xa4b2af31, 0xadbfa43f, 0xb6a8b92d, 0xbfa5b223, 0x80868309, 0x898b8807, 0x929c9515, 0x9b919e1b, 0x7c0a47a1, 0x75074caf, 0x6e1051bd, 0x671d5ab3, 0x583e6b99, 0x51336097, 0x4a247d85, 0x4329768b, 0x34621fd1, 0x3d6f14df, 0x267809cd, 0x2f7502c3, 0x105633e9, 0x195b38e7, 0x024c25f5, 0x0b412efb, 0xd7618c9a, 0xde6c8794, 0xc57b9a86, 0xcc769188, 0xf355a0a2, 0xfa58abac, 0xe14fb6be, 0xe842bdb0, 0x9f09d4ea, 0x9604dfe4, 0x8d13c2f6, 0x841ec9f8, 0xbb3df8d2, 0xb230f3dc, 0xa927eece, 0xa02ae5c0, 0x47b13c7a, 0x4ebc3774, 0x55ab2a66, 0x5ca62168, 0x63851042, 0x6a881b4c, 0x719f065e, 0x78920d50, 0x0fd9640a, 0x06d46f04, 0x1dc37216, 0x14ce7918, 0x2bed4832, 0x22e0433c, 0x39f75e2e, 0x30fa5520, 0x9ab701ec, 0x93ba0ae2, 0x88ad17f0, 0x81a01cfe, 0xbe832dd4, 0xb78e26da, 0xac993bc8, 0xa59430c6, 0xd2df599c, 0xdbd25292, 0xc0c54f80, 0xc9c8448e, 0xf6eb75a4, 0xffe67eaa, 0xe4f163b8, 0xedfc68b6, 0x0a67b10c, 0x036aba02, 0x187da710, 0x1170ac1e, 0x2e539d34, 0x275e963a, 0x3c498b28, 0x35448026, 0x420fe97c, 0x4b02e272, 0x5015ff60, 0x5918f46e, 0x663bc544, 0x6f36ce4a, 0x7421d358, 0x7d2cd856, 0xa10c7a37, 0xa8017139, 0xb3166c2b, 0xba1b6725, 0x8538560f, 0x8c355d01, 0x97224013, 0x9e2f4b1d, 0xe9642247, 0xe0692949, 0xfb7e345b, 0xf2733f55, 0xcd500e7f, 0xc45d0571, 0xdf4a1863, 0xd647136d, 0x31dccad7, 0x38d1c1d9, 0x23c6dccb, 0x2acbd7c5, 0x15e8e6ef, 0x1ce5ede1, 0x07f2f0f3, 0x0efffbfd, 0x79b492a7, 0x70b999a9, 0x6bae84bb, 0x62a38fb5, 0x5d80be9f, 0x548db591, 0x4f9aa883, 0x4697a38d];
32066 function convertToInt32(bytes) {
32069 for (var i = 0; i < bytes.length; i += 4) {
32070 result.push(bytes[i] << 24 | bytes[i + 1] << 16 | bytes[i + 2] << 8 | bytes[i + 3]);
32076 var AES = function AES(key) {
32077 if (!(this instanceof AES)) {
32078 throw Error('AES must be instanitated with `new`');
32081 Object.defineProperty(this, 'key', {
32082 value: coerceArray(key, true)
32088 AES.prototype._prepare = function () {
32089 var rounds = numberOfRounds[this.key.length];
32091 if (rounds == null) {
32092 throw new Error('invalid key size (must be 16, 24 or 32 bytes)');
32093 } // encryption round keys
32096 this._Ke = []; // decryption round keys
32100 for (var i = 0; i <= rounds; i++) {
32101 this._Ke.push([0, 0, 0, 0]);
32103 this._Kd.push([0, 0, 0, 0]);
32106 var roundKeyCount = (rounds + 1) * 4;
32107 var KC = this.key.length / 4; // convert the key into ints
32109 var tk = convertToInt32(this.key); // copy values into round key arrays
32113 for (var i = 0; i < KC; i++) {
32115 this._Ke[index][i % 4] = tk[i];
32116 this._Kd[rounds - index][i % 4] = tk[i];
32117 } // key expansion (fips-197 section 5.2)
32120 var rconpointer = 0;
32124 while (t < roundKeyCount) {
32126 tk[0] ^= S[tt >> 16 & 0xFF] << 24 ^ S[tt >> 8 & 0xFF] << 16 ^ S[tt & 0xFF] << 8 ^ S[tt >> 24 & 0xFF] ^ rcon[rconpointer] << 24;
32127 rconpointer += 1; // key expansion (for non-256 bit)
32130 for (var i = 1; i < KC; i++) {
32131 tk[i] ^= tk[i - 1];
32132 } // key expansion for 256-bit keys is "slightly different" (fips-197)
32135 for (var i = 1; i < KC / 2; i++) {
32136 tk[i] ^= tk[i - 1];
32139 tt = tk[KC / 2 - 1];
32140 tk[KC / 2] ^= S[tt & 0xFF] ^ S[tt >> 8 & 0xFF] << 8 ^ S[tt >> 16 & 0xFF] << 16 ^ S[tt >> 24 & 0xFF] << 24;
32142 for (var i = KC / 2 + 1; i < KC; i++) {
32143 tk[i] ^= tk[i - 1];
32145 } // copy values into round key arrays
32152 while (i < KC && t < roundKeyCount) {
32155 this._Ke[r][c] = tk[i];
32156 this._Kd[rounds - r][c] = tk[i++];
32159 } // inverse-cipher-ify the decryption round key (fips-197 section 5.3)
32162 for (var r = 1; r < rounds; r++) {
32163 for (var c = 0; c < 4; c++) {
32164 tt = this._Kd[r][c];
32165 this._Kd[r][c] = U1[tt >> 24 & 0xFF] ^ U2[tt >> 16 & 0xFF] ^ U3[tt >> 8 & 0xFF] ^ U4[tt & 0xFF];
32170 AES.prototype.encrypt = function (plaintext) {
32171 if (plaintext.length != 16) {
32172 throw new Error('invalid plaintext size (must be 16 bytes)');
32175 var rounds = this._Ke.length - 1;
32176 var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
32178 var t = convertToInt32(plaintext);
32180 for (var i = 0; i < 4; i++) {
32181 t[i] ^= this._Ke[0][i];
32182 } // apply round transforms
32185 for (var r = 1; r < rounds; r++) {
32186 for (var i = 0; i < 4; i++) {
32187 a[i] = T1[t[i] >> 24 & 0xff] ^ T2[t[(i + 1) % 4] >> 16 & 0xff] ^ T3[t[(i + 2) % 4] >> 8 & 0xff] ^ T4[t[(i + 3) % 4] & 0xff] ^ this._Ke[r][i];
32191 } // the last round is special
32194 var result = createArray(16),
32197 for (var i = 0; i < 4; i++) {
32198 tt = this._Ke[rounds][i];
32199 result[4 * i] = (S[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
32200 result[4 * i + 1] = (S[t[(i + 1) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
32201 result[4 * i + 2] = (S[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
32202 result[4 * i + 3] = (S[t[(i + 3) % 4] & 0xff] ^ tt) & 0xff;
32208 AES.prototype.decrypt = function (ciphertext) {
32209 if (ciphertext.length != 16) {
32210 throw new Error('invalid ciphertext size (must be 16 bytes)');
32213 var rounds = this._Kd.length - 1;
32214 var a = [0, 0, 0, 0]; // convert plaintext to (ints ^ key)
32216 var t = convertToInt32(ciphertext);
32218 for (var i = 0; i < 4; i++) {
32219 t[i] ^= this._Kd[0][i];
32220 } // apply round transforms
32223 for (var r = 1; r < rounds; r++) {
32224 for (var i = 0; i < 4; i++) {
32225 a[i] = T5[t[i] >> 24 & 0xff] ^ T6[t[(i + 3) % 4] >> 16 & 0xff] ^ T7[t[(i + 2) % 4] >> 8 & 0xff] ^ T8[t[(i + 1) % 4] & 0xff] ^ this._Kd[r][i];
32229 } // the last round is special
32232 var result = createArray(16),
32235 for (var i = 0; i < 4; i++) {
32236 tt = this._Kd[rounds][i];
32237 result[4 * i] = (Si[t[i] >> 24 & 0xff] ^ tt >> 24) & 0xff;
32238 result[4 * i + 1] = (Si[t[(i + 3) % 4] >> 16 & 0xff] ^ tt >> 16) & 0xff;
32239 result[4 * i + 2] = (Si[t[(i + 2) % 4] >> 8 & 0xff] ^ tt >> 8) & 0xff;
32240 result[4 * i + 3] = (Si[t[(i + 1) % 4] & 0xff] ^ tt) & 0xff;
32246 * Mode Of Operation - Electonic Codebook (ECB)
32250 var ModeOfOperationECB = function ModeOfOperationECB(key) {
32251 if (!(this instanceof ModeOfOperationECB)) {
32252 throw Error('AES must be instanitated with `new`');
32255 this.description = "Electronic Code Block";
32257 this._aes = new AES(key);
32260 ModeOfOperationECB.prototype.encrypt = function (plaintext) {
32261 plaintext = coerceArray(plaintext);
32263 if (plaintext.length % 16 !== 0) {
32264 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
32267 var ciphertext = createArray(plaintext.length);
32268 var block = createArray(16);
32270 for (var i = 0; i < plaintext.length; i += 16) {
32271 copyArray(plaintext, block, 0, i, i + 16);
32272 block = this._aes.encrypt(block);
32273 copyArray(block, ciphertext, i);
32279 ModeOfOperationECB.prototype.decrypt = function (ciphertext) {
32280 ciphertext = coerceArray(ciphertext);
32282 if (ciphertext.length % 16 !== 0) {
32283 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
32286 var plaintext = createArray(ciphertext.length);
32287 var block = createArray(16);
32289 for (var i = 0; i < ciphertext.length; i += 16) {
32290 copyArray(ciphertext, block, 0, i, i + 16);
32291 block = this._aes.decrypt(block);
32292 copyArray(block, plaintext, i);
32298 * Mode Of Operation - Cipher Block Chaining (CBC)
32302 var ModeOfOperationCBC = function ModeOfOperationCBC(key, iv) {
32303 if (!(this instanceof ModeOfOperationCBC)) {
32304 throw Error('AES must be instanitated with `new`');
32307 this.description = "Cipher Block Chaining";
32311 iv = createArray(16);
32312 } else if (iv.length != 16) {
32313 throw new Error('invalid initialation vector size (must be 16 bytes)');
32316 this._lastCipherblock = coerceArray(iv, true);
32317 this._aes = new AES(key);
32320 ModeOfOperationCBC.prototype.encrypt = function (plaintext) {
32321 plaintext = coerceArray(plaintext);
32323 if (plaintext.length % 16 !== 0) {
32324 throw new Error('invalid plaintext size (must be multiple of 16 bytes)');
32327 var ciphertext = createArray(plaintext.length);
32328 var block = createArray(16);
32330 for (var i = 0; i < plaintext.length; i += 16) {
32331 copyArray(plaintext, block, 0, i, i + 16);
32333 for (var j = 0; j < 16; j++) {
32334 block[j] ^= this._lastCipherblock[j];
32337 this._lastCipherblock = this._aes.encrypt(block);
32338 copyArray(this._lastCipherblock, ciphertext, i);
32344 ModeOfOperationCBC.prototype.decrypt = function (ciphertext) {
32345 ciphertext = coerceArray(ciphertext);
32347 if (ciphertext.length % 16 !== 0) {
32348 throw new Error('invalid ciphertext size (must be multiple of 16 bytes)');
32351 var plaintext = createArray(ciphertext.length);
32352 var block = createArray(16);
32354 for (var i = 0; i < ciphertext.length; i += 16) {
32355 copyArray(ciphertext, block, 0, i, i + 16);
32356 block = this._aes.decrypt(block);
32358 for (var j = 0; j < 16; j++) {
32359 plaintext[i + j] = block[j] ^ this._lastCipherblock[j];
32362 copyArray(ciphertext, this._lastCipherblock, 0, i, i + 16);
32368 * Mode Of Operation - Cipher Feedback (CFB)
32372 var ModeOfOperationCFB = function ModeOfOperationCFB(key, iv, segmentSize) {
32373 if (!(this instanceof ModeOfOperationCFB)) {
32374 throw Error('AES must be instanitated with `new`');
32377 this.description = "Cipher Feedback";
32381 iv = createArray(16);
32382 } else if (iv.length != 16) {
32383 throw new Error('invalid initialation vector size (must be 16 size)');
32386 if (!segmentSize) {
32390 this.segmentSize = segmentSize;
32391 this._shiftRegister = coerceArray(iv, true);
32392 this._aes = new AES(key);
32395 ModeOfOperationCFB.prototype.encrypt = function (plaintext) {
32396 if (plaintext.length % this.segmentSize != 0) {
32397 throw new Error('invalid plaintext size (must be segmentSize bytes)');
32400 var encrypted = coerceArray(plaintext, true);
32403 for (var i = 0; i < encrypted.length; i += this.segmentSize) {
32404 xorSegment = this._aes.encrypt(this._shiftRegister);
32406 for (var j = 0; j < this.segmentSize; j++) {
32407 encrypted[i + j] ^= xorSegment[j];
32408 } // Shift the register
32411 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
32412 copyArray(encrypted, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
32418 ModeOfOperationCFB.prototype.decrypt = function (ciphertext) {
32419 if (ciphertext.length % this.segmentSize != 0) {
32420 throw new Error('invalid ciphertext size (must be segmentSize bytes)');
32423 var plaintext = coerceArray(ciphertext, true);
32426 for (var i = 0; i < plaintext.length; i += this.segmentSize) {
32427 xorSegment = this._aes.encrypt(this._shiftRegister);
32429 for (var j = 0; j < this.segmentSize; j++) {
32430 plaintext[i + j] ^= xorSegment[j];
32431 } // Shift the register
32434 copyArray(this._shiftRegister, this._shiftRegister, 0, this.segmentSize);
32435 copyArray(ciphertext, this._shiftRegister, 16 - this.segmentSize, i, i + this.segmentSize);
32441 * Mode Of Operation - Output Feedback (OFB)
32445 var ModeOfOperationOFB = function ModeOfOperationOFB(key, iv) {
32446 if (!(this instanceof ModeOfOperationOFB)) {
32447 throw Error('AES must be instanitated with `new`');
32450 this.description = "Output Feedback";
32454 iv = createArray(16);
32455 } else if (iv.length != 16) {
32456 throw new Error('invalid initialation vector size (must be 16 bytes)');
32459 this._lastPrecipher = coerceArray(iv, true);
32460 this._lastPrecipherIndex = 16;
32461 this._aes = new AES(key);
32464 ModeOfOperationOFB.prototype.encrypt = function (plaintext) {
32465 var encrypted = coerceArray(plaintext, true);
32467 for (var i = 0; i < encrypted.length; i++) {
32468 if (this._lastPrecipherIndex === 16) {
32469 this._lastPrecipher = this._aes.encrypt(this._lastPrecipher);
32470 this._lastPrecipherIndex = 0;
32473 encrypted[i] ^= this._lastPrecipher[this._lastPrecipherIndex++];
32477 }; // Decryption is symetric
32480 ModeOfOperationOFB.prototype.decrypt = ModeOfOperationOFB.prototype.encrypt;
32482 * Counter object for CTR common mode of operation
32485 var Counter = function Counter(initialValue) {
32486 if (!(this instanceof Counter)) {
32487 throw Error('Counter must be instanitated with `new`');
32488 } // We allow 0, but anything false-ish uses the default 1
32491 if (initialValue !== 0 && !initialValue) {
32495 if (typeof initialValue === 'number') {
32496 this._counter = createArray(16);
32497 this.setValue(initialValue);
32499 this.setBytes(initialValue);
32503 Counter.prototype.setValue = function (value) {
32504 if (typeof value !== 'number' || parseInt(value) != value) {
32505 throw new Error('invalid counter value (must be an integer)');
32506 } // We cannot safely handle numbers beyond the safe range for integers
32509 if (value > Number.MAX_SAFE_INTEGER) {
32510 throw new Error('integer value out of safe range');
32513 for (var index = 15; index >= 0; --index) {
32514 this._counter[index] = value % 256;
32515 value = parseInt(value / 256);
32519 Counter.prototype.setBytes = function (bytes) {
32520 bytes = coerceArray(bytes, true);
32522 if (bytes.length != 16) {
32523 throw new Error('invalid counter bytes size (must be 16 bytes)');
32526 this._counter = bytes;
32529 Counter.prototype.increment = function () {
32530 for (var i = 15; i >= 0; i--) {
32531 if (this._counter[i] === 255) {
32532 this._counter[i] = 0;
32534 this._counter[i]++;
32540 * Mode Of Operation - Counter (CTR)
32544 var ModeOfOperationCTR = function ModeOfOperationCTR(key, counter) {
32545 if (!(this instanceof ModeOfOperationCTR)) {
32546 throw Error('AES must be instanitated with `new`');
32549 this.description = "Counter";
32552 if (!(counter instanceof Counter)) {
32553 counter = new Counter(counter);
32556 this._counter = counter;
32557 this._remainingCounter = null;
32558 this._remainingCounterIndex = 16;
32559 this._aes = new AES(key);
32562 ModeOfOperationCTR.prototype.encrypt = function (plaintext) {
32563 var encrypted = coerceArray(plaintext, true);
32565 for (var i = 0; i < encrypted.length; i++) {
32566 if (this._remainingCounterIndex === 16) {
32567 this._remainingCounter = this._aes.encrypt(this._counter._counter);
32568 this._remainingCounterIndex = 0;
32570 this._counter.increment();
32573 encrypted[i] ^= this._remainingCounter[this._remainingCounterIndex++];
32577 }; // Decryption is symetric
32580 ModeOfOperationCTR.prototype.decrypt = ModeOfOperationCTR.prototype.encrypt; ///////////////////////
32582 // See:https://tools.ietf.org/html/rfc2315
32584 function pkcs7pad(data) {
32585 data = coerceArray(data, true);
32586 var padder = 16 - data.length % 16;
32587 var result = createArray(data.length + padder);
32588 copyArray(data, result);
32590 for (var i = data.length; i < result.length; i++) {
32591 result[i] = padder;
32597 function pkcs7strip(data) {
32598 data = coerceArray(data, true);
32600 if (data.length < 16) {
32601 throw new Error('PKCS#7 invalid length');
32604 var padder = data[data.length - 1];
32607 throw new Error('PKCS#7 padding byte out of range');
32610 var length = data.length - padder;
32612 for (var i = 0; i < padder; i++) {
32613 if (data[length + i] !== padder) {
32614 throw new Error('PKCS#7 invalid padding byte');
32618 var result = createArray(length);
32619 copyArray(data, result, 0, 0, length);
32621 } ///////////////////////
32623 // The block cipher
32630 ecb: ModeOfOperationECB,
32631 cbc: ModeOfOperationCBC,
32632 cfb: ModeOfOperationCFB,
32633 ofb: ModeOfOperationOFB,
32634 ctr: ModeOfOperationCTR
32647 coerceArray: coerceArray,
32648 createArray: createArray,
32649 copyArray: copyArray
32654 module.exports = aesjs; // RequireJS/AMD
32655 // http://www.requirejs.org/docs/api.html
32656 // https://github.com/amdjs/amdjs-api/wiki/AMD
32661 var aesjs = aesJs.exports;
32663 // We can use keys that are 128 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 bytes).
32664 // To generate a random key: window.crypto.getRandomValues(new Uint8Array(16));
32665 // This default signing key is built into iD and can be used to mask/unmask sensitive values.
32667 var DEFAULT_128 = [250, 157, 60, 79, 142, 134, 229, 129, 138, 126, 210, 129, 29, 71, 160, 208];
32668 function utilAesEncrypt(text, key) {
32669 key = key || DEFAULT_128;
32670 var textBytes = aesjs.utils.utf8.toBytes(text);
32671 var aesCtr = new aesjs.ModeOfOperation.ctr(key);
32672 var encryptedBytes = aesCtr.encrypt(textBytes);
32673 var encryptedHex = aesjs.utils.hex.fromBytes(encryptedBytes);
32674 return encryptedHex;
32676 function utilAesDecrypt(encryptedHex, key) {
32677 key = key || DEFAULT_128;
32678 var encryptedBytes = aesjs.utils.hex.toBytes(encryptedHex);
32679 var aesCtr = new aesjs.ModeOfOperation.ctr(key);
32680 var decryptedBytes = aesCtr.decrypt(encryptedBytes);
32681 var text = aesjs.utils.utf8.fromBytes(decryptedBytes);
32685 function utilCleanTags(tags) {
32688 for (var k in tags) {
32692 if (v !== undefined) {
32693 out[k] = cleanValue(k, v);
32699 function cleanValue(k, v) {
32700 function keepSpaces(k) {
32701 return /_hours|_times|:conditional$/.test(k);
32705 return /^(description|note|fixme)$/.test(k);
32708 if (skip(k)) return v;
32709 var cleaned = v.split(';').map(function (s) {
32711 }).join(keepSpaces(k) ? '; ' : ';'); // The code below is not intended to validate websites and emails.
32712 // It is only intended to prevent obvious copy-paste errors. (#2323)
32713 // clean website- and email-like tags
32715 if (k.indexOf('website') !== -1 || k.indexOf('email') !== -1 || cleaned.indexOf('http') === 0) {
32716 cleaned = cleaned.replace(/[\u200B-\u200F\uFEFF]/g, ''); // strip LRM and other zero width chars
32725 function utilDetect(refresh) {
32726 if (_detected && !refresh) return _detected;
32728 var ua = navigator.userAgent;
32732 m = ua.match(/(edge)\/?\s*(\.?\d+(\.\d+)*)/i); // Edge
32735 _detected.browser = m[1];
32736 _detected.version = m[2];
32739 if (!_detected.browser) {
32740 m = ua.match(/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/i); // IE11
32743 _detected.browser = 'msie';
32744 _detected.version = m[1];
32748 if (!_detected.browser) {
32749 m = ua.match(/(opr)\/?\s*(\.?\d+(\.\d+)*)/i); // Opera 15+
32752 _detected.browser = 'Opera';
32753 _detected.version = m[2];
32757 if (!_detected.browser) {
32758 m = ua.match(/(opera|chrome|safari|firefox|msie)\/?\s*(\.?\d+(\.\d+)*)/i);
32761 _detected.browser = m[1];
32762 _detected.version = m[2];
32763 m = ua.match(/version\/([\.\d]+)/i);
32764 if (m !== null) _detected.version = m[1];
32768 if (!_detected.browser) {
32769 _detected.browser = navigator.appName;
32770 _detected.version = navigator.appVersion;
32771 } // keep major.minor version only..
32774 _detected.version = _detected.version.split(/\W/).slice(0, 2).join('.'); // detect other browser capabilities
32775 // Legacy Opera has incomplete svg style support. See #715
32777 _detected.opera = _detected.browser.toLowerCase() === 'opera' && parseFloat(_detected.version) < 15;
32779 if (_detected.browser.toLowerCase() === 'msie') {
32780 _detected.ie = true;
32781 _detected.browser = 'Internet Explorer';
32782 _detected.support = parseFloat(_detected.version) >= 11;
32784 _detected.ie = false;
32785 _detected.support = true;
32788 _detected.filedrop = window.FileReader && 'ondrop' in window;
32789 _detected.download = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
32790 _detected.cssfilters = !(_detected.ie || _detected.browser.toLowerCase() === 'edge');
32793 if (/Win/.test(ua)) {
32794 _detected.os = 'win';
32795 _detected.platform = 'Windows';
32796 } else if (/Mac/.test(ua)) {
32797 _detected.os = 'mac';
32798 _detected.platform = 'Macintosh';
32799 } else if (/X11/.test(ua) || /Linux/.test(ua)) {
32800 _detected.os = 'linux';
32801 _detected.platform = 'Linux';
32803 _detected.os = 'win';
32804 _detected.platform = 'Unknown';
32807 _detected.isMobileWebKit = (/\b(iPad|iPhone|iPod)\b/.test(ua) || // HACK: iPadOS 13+ requests desktop sites by default by using a Mac user agent,
32808 // so assume any "mac" with multitouch is actually iOS
32809 navigator.platform === 'MacIntel' && 'maxTouchPoints' in navigator && navigator.maxTouchPoints > 1) && /WebKit/.test(ua) && !/Edge/.test(ua) && !window.MSStream;
32811 // An array of locales requested by the browser in priority order.
32813 _detected.browserLocales = Array.from(new Set( // remove duplicates
32814 [navigator.language].concat(navigator.languages || []).concat([// old property for backwards compatibility
32815 navigator.userLanguage]) // remove any undefined values
32816 .filter(Boolean)));
32819 var loc = window.top.location;
32820 var origin = loc.origin;
32823 // for unpatched IE11
32824 origin = loc.protocol + '//' + loc.hostname + (loc.port ? ':' + loc.port : '');
32827 _detected.host = origin + loc.pathname;
32831 // Like selection.property('value', ...), but avoids no-op value sets,
32832 // which can result in layout/repaint thrashing in some situations.
32833 function utilGetSetValue(selection, value) {
32834 function d3_selection_value(value) {
32835 function valueNull() {
32839 function valueConstant() {
32840 if (this.value !== value) {
32841 this.value = value;
32845 function valueFunction() {
32846 var x = value.apply(this, arguments);
32848 if (x === null || x === undefined) {
32850 } else if (this.value !== x) {
32855 return value === null || value === undefined ? valueNull : typeof value === 'function' ? valueFunction : valueConstant;
32858 if (arguments.length === 1) {
32859 return selection.property('value');
32862 return selection.each(d3_selection_value(value));
32865 function utilKeybinding(namespace) {
32866 var _keybindings = {};
32868 function testBindings(d3_event, isCapturing) {
32869 var didMatch = false;
32870 var bindings = Object.keys(_keybindings).map(function (id) {
32871 return _keybindings[id];
32873 var i, binding; // Most key shortcuts will accept either lower or uppercase ('h' or 'H'),
32874 // so we don't strictly match on the shift key, but we prioritize
32875 // shifted keybindings first, and fallback to unshifted only if no match.
32876 // (This lets us differentiate between '←'/'⇧←' or '⌘Z'/'⌘⇧Z')
32877 // priority match shifted keybindings first
32879 for (i = 0; i < bindings.length; i++) {
32880 binding = bindings[i];
32881 if (!binding.event.modifiers.shiftKey) continue; // no shift
32883 if (!!binding.capture !== isCapturing) continue;
32885 if (matches(d3_event, binding, true)) {
32886 binding.callback(d3_event);
32887 didMatch = true; // match a max of one binding per event
32893 if (didMatch) return; // then unshifted keybindings
32895 for (i = 0; i < bindings.length; i++) {
32896 binding = bindings[i];
32897 if (binding.event.modifiers.shiftKey) continue; // shift
32899 if (!!binding.capture !== isCapturing) continue;
32901 if (matches(d3_event, binding, false)) {
32902 binding.callback(d3_event);
32907 function matches(d3_event, binding, testShift) {
32908 var event = d3_event;
32909 var isMatch = false;
32910 var tryKeyCode = true; // Prefer a match on `KeyboardEvent.key`
32912 if (event.key !== undefined) {
32913 tryKeyCode = event.key.charCodeAt(0) > 255; // outside ISO-Latin-1
32917 if (binding.event.key === undefined) {
32919 } else if (Array.isArray(binding.event.key)) {
32920 if (binding.event.key.map(function (s) {
32921 return s.toLowerCase();
32922 }).indexOf(event.key.toLowerCase()) === -1) {
32926 if (event.key.toLowerCase() !== binding.event.key.toLowerCase()) {
32930 } // Fallback match on `KeyboardEvent.keyCode`, can happen if:
32931 // - browser doesn't support `KeyboardEvent.key`
32932 // - `KeyboardEvent.key` is outside ISO-Latin-1 range (cyrillic?)
32935 if (!isMatch && tryKeyCode) {
32936 isMatch = event.keyCode === binding.event.keyCode;
32939 if (!isMatch) return false; // test modifier keys
32941 if (!(event.ctrlKey && event.altKey)) {
32942 // if both are set, assume AltGr and skip it - #4096
32943 if (event.ctrlKey !== binding.event.modifiers.ctrlKey) return false;
32944 if (event.altKey !== binding.event.modifiers.altKey) return false;
32947 if (event.metaKey !== binding.event.modifiers.metaKey) return false;
32948 if (testShift && event.shiftKey !== binding.event.modifiers.shiftKey) return false;
32953 function capture(d3_event) {
32954 testBindings(d3_event, true);
32957 function bubble(d3_event) {
32958 var tagName = select(d3_event.target).node().tagName;
32960 if (tagName === 'INPUT' || tagName === 'SELECT' || tagName === 'TEXTAREA') {
32964 testBindings(d3_event, false);
32967 function keybinding(selection) {
32968 selection = selection || select(document);
32969 selection.on('keydown.capture.' + namespace, capture, true);
32970 selection.on('keydown.bubble.' + namespace, bubble, false);
32972 } // was: keybinding.off()
32975 keybinding.unbind = function (selection) {
32977 selection = selection || select(document);
32978 selection.on('keydown.capture.' + namespace, null);
32979 selection.on('keydown.bubble.' + namespace, null);
32983 keybinding.clear = function () {
32986 }; // Remove one or more keycode bindings.
32989 keybinding.off = function (codes, capture) {
32990 var arr = utilArrayUniq([].concat(codes));
32992 for (var i = 0; i < arr.length; i++) {
32993 var id = arr[i] + (capture ? '-capture' : '-bubble');
32994 delete _keybindings[id];
32998 }; // Add one or more keycode bindings.
33001 keybinding.on = function (codes, callback, capture) {
33002 if (typeof callback !== 'function') {
33003 return keybinding.off(codes, capture);
33006 var arr = utilArrayUniq([].concat(codes));
33008 for (var i = 0; i < arr.length; i++) {
33009 var id = arr[i] + (capture ? '-capture' : '-bubble');
33013 callback: callback,
33028 if (_keybindings[id]) {
33029 console.warn('warning: duplicate keybinding for "' + id + '"'); // eslint-disable-line no-console
33032 _keybindings[id] = binding;
33033 var matches = arr[i].toLowerCase().match(/(?:(?:[^+⇧⌃⌥⌘])+|[⇧⌃⌥⌘]|\+\+|^\+$)/g);
33035 for (var j = 0; j < matches.length; j++) {
33036 // Normalise matching errors
33037 if (matches[j] === '++') matches[j] = '+';
33039 if (matches[j] in utilKeybinding.modifierCodes) {
33040 var prop = utilKeybinding.modifierProperties[utilKeybinding.modifierCodes[matches[j]]];
33041 binding.event.modifiers[prop] = true;
33043 binding.event.key = utilKeybinding.keys[matches[j]] || matches[j];
33045 if (matches[j] in utilKeybinding.keyCodes) {
33046 binding.event.keyCode = utilKeybinding.keyCodes[matches[j]];
33058 * See https://github.com/keithamus/jwerty
33061 utilKeybinding.modifierCodes = {
33065 // CTRL key, on Mac: ⌃
33068 // ALT key, on Mac: ⌥ (Alt)
33072 // META, on Mac: ⌘ (CMD), on Windows (Win), on Linux (Super)
33079 utilKeybinding.modifierProperties = {
33085 utilKeybinding.plusKeys = ['plus', 'ffplus', '=', 'ffequals', '≠', '±'];
33086 utilKeybinding.minusKeys = ['_', '-', 'ffminus', 'dash', '–', '—'];
33087 utilKeybinding.keys = {
33088 // Backspace key, on Mac: ⌫ (Backspace)
33090 backspace: 'Backspace',
33091 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
33104 'pause-break': 'Pause',
33105 // Caps Lock key, ⇪
33108 'caps-lock': 'CapsLock',
33109 // Escape key, on Mac: ⎋, on Windows: Esc
33110 '⎋': ['Escape', 'Esc'],
33111 escape: ['Escape', 'Esc'],
33112 esc: ['Escape', 'Esc'],
33114 space: [' ', 'Spacebar'],
33115 // Page-Up key, or pgup, on Mac: ↖
33118 'page-up': 'PageUp',
33119 // Page-Down key, or pgdown, on Mac: ↘
33121 pgdown: 'PageDown',
33122 'page-down': 'PageDown',
33123 // END key, on Mac: ⇟
33126 // HOME key, on Mac: ⇞
33129 // Insert key, or ins
33132 // Delete key, on Mac: ⌦ (Delete)
33133 '⌦': ['Delete', 'Del'],
33134 del: ['Delete', 'Del'],
33135 'delete': ['Delete', 'Del'],
33136 // Left Arrow Key, or ←
33137 '←': ['ArrowLeft', 'Left'],
33138 left: ['ArrowLeft', 'Left'],
33139 'arrow-left': ['ArrowLeft', 'Left'],
33140 // Up Arrow Key, or ↑
33141 '↑': ['ArrowUp', 'Up'],
33142 up: ['ArrowUp', 'Up'],
33143 'arrow-up': ['ArrowUp', 'Up'],
33144 // Right Arrow Key, or →
33145 '→': ['ArrowRight', 'Right'],
33146 right: ['ArrowRight', 'Right'],
33147 'arrow-right': ['ArrowRight', 'Right'],
33148 // Up Arrow Key, or ↓
33149 '↓': ['ArrowDown', 'Down'],
33150 down: ['ArrowDown', 'Down'],
33151 'arrow-down': ['ArrowDown', 'Down'],
33152 // odities, stuff for backward compatibility (browsers and code):
33153 // Num-Multiply, or *
33154 '*': ['*', 'Multiply'],
33155 star: ['*', 'Multiply'],
33156 asterisk: ['*', 'Multiply'],
33157 multiply: ['*', 'Multiply'],
33160 'plus': ['+', 'Add'],
33161 // Num-Subtract, or -
33162 '-': ['-', 'Subtract'],
33163 subtract: ['-', 'Subtract'],
33164 'dash': ['-', 'Subtract'],
33171 // Period, or ., or full-stop
33174 // Slash, or /, or forward-slash
33176 'forward-slash': '/',
33177 // Tick, or `, or back-quote
33180 // Open bracket, or [
33181 'open-bracket': '[',
33182 // Back slash, or \
33183 'back-slash': '\\',
33184 // Close backet, or ]
33185 'close-bracket': ']',
33186 // Apostrophe, or Quote, or '
33227 utilKeybinding.keyCodes = {
33228 // Backspace key, on Mac: ⌫ (Backspace)
33231 // Tab Key, on Mac: ⇥ (Tab), on Windows ⇥⇥
33245 // Caps Lock key, ⇪
33249 // Escape key, on Mac: ⎋, on Windows: Esc
33255 // Page-Up key, or pgup, on Mac: ↖
33259 // Page-Down key, or pgdown, on Mac: ↘
33263 // END key, on Mac: ⇟
33266 // HOME key, on Mac: ⇞
33269 // Insert key, or ins
33272 // Delete key, on Mac: ⌦ (Delete)
33276 // Left Arrow Key, or ←
33280 // Up Arrow Key, or ↑
33284 // Right Arrow Key, or →
33288 // Up Arrow Key, or ↓
33292 // odities, printing characters that come out wrong:
33295 // Num-Multiply, or *
33303 // Num-Subtract, or -
33306 // Vertical Bar / Pipe
33321 // Dash / Underscore key
33323 // Period, or ., or full-stop
33327 // Slash, or /, or forward-slash
33330 'forward-slash': 191,
33331 // Tick, or `, or back-quote
33335 // Open bracket, or [
33337 'open-bracket': 219,
33338 // Back slash, or \
33341 // Close backet, or ]
33343 'close-bracket': 221,
33344 // Apostrophe, or Quote, or '
33353 while (++i < 106) {
33354 utilKeybinding.keyCodes['num-' + n] = i;
33363 utilKeybinding.keyCodes[n] = i;
33371 while (++i < 136) {
33372 utilKeybinding.keyCodes['f' + n] = i;
33380 utilKeybinding.keyCodes[String.fromCharCode(i).toLowerCase()] = i;
33383 function utilObjectOmit(obj, omitKeys) {
33384 return Object.keys(obj).reduce(function (result, key) {
33385 if (omitKeys.indexOf(key) === -1) {
33386 result[key] = obj[key]; // keep
33393 // Copies a variable number of methods from source to target.
33394 function utilRebind(target, source) {
33396 n = arguments.length,
33400 target[method = arguments[i]] = d3_rebind(target, source, source[method]);
33404 } // Method is assumed to be a standard D3 getter-setter:
33405 // If passed with no arguments, gets the value.
33406 // If passed with arguments, sets the value and returns the target.
33408 function d3_rebind(target, source, method) {
33409 return function () {
33410 var value = method.apply(source, arguments);
33411 return value === source ? target : value;
33415 // A per-domain session mutex backed by a cookie and dead man's
33416 // switch. If the session crashes, the mutex will auto-release
33417 // after 5 seconds.
33418 // This accepts a string and returns an object that complies with utilSessionMutexType
33419 function utilSessionMutex(name) {
33424 var expires = new Date();
33425 expires.setSeconds(expires.getSeconds() + 5);
33426 document.cookie = name + '=1; expires=' + expires.toUTCString() + '; sameSite=strict';
33429 mutex.lock = function () {
33430 if (intervalID) return true;
33431 var cookie = document.cookie.replace(new RegExp('(?:(?:^|.*;)\\s*' + name + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
33432 if (cookie) return false;
33434 intervalID = window.setInterval(renew, 4000);
33438 mutex.unlock = function () {
33439 if (!intervalID) return;
33440 document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; sameSite=strict';
33441 clearInterval(intervalID);
33445 mutex.locked = function () {
33446 return !!intervalID;
33452 function utilTiler() {
33453 var _size = [256, 256];
33455 var _tileSize = 256;
33456 var _zoomExtent = [0, 20];
33457 var _translate = [_size[0] / 2, _size[1] / 2];
33459 var _skipNullIsland = false;
33461 function clamp(num, min, max) {
33462 return Math.max(min, Math.min(num, max));
33465 function nearNullIsland(tile) {
33471 var center = Math.pow(2, z - 1);
33472 var width = Math.pow(2, z - 6);
33473 var min = center - width / 2;
33474 var max = center + width / 2 - 1;
33475 return x >= min && x <= max && y >= min && y <= max;
33482 var z = geoScaleToZoom(_scale / (2 * Math.PI), _tileSize);
33483 var z0 = clamp(Math.round(z), _zoomExtent[0], _zoomExtent[1]);
33485 var tileMax = Math.pow(2, z0) - 1;
33486 var log2ts = Math.log(_tileSize) * Math.LOG2E;
33487 var k = Math.pow(2, z - z0 + log2ts);
33488 var origin = [(_translate[0] - _scale / 2) / k, (_translate[1] - _scale / 2) / k];
33489 var cols = range$1(clamp(Math.floor(-origin[0]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[0] / k - origin[0]) + _margin, tileMin, tileMax + 1));
33490 var rows = range$1(clamp(Math.floor(-origin[1]) - _margin, tileMin, tileMax + 1), clamp(Math.ceil(_size[1] / k - origin[1]) + _margin, tileMin, tileMax + 1));
33493 for (var i = 0; i < rows.length; i++) {
33496 for (var j = 0; j < cols.length; j++) {
33499 if (i >= _margin && i <= rows.length - _margin && j >= _margin && j <= cols.length - _margin) {
33500 tiles.unshift([x, y, z0]); // tiles in view at beginning
33502 tiles.push([x, y, z0]); // tiles in margin at the end
33507 tiles.translate = origin;
33512 * getTiles() returns an array of tiles that cover the map view
33516 tiler.getTiles = function (projection) {
33517 var origin = [projection.scale() * Math.PI - projection.translate()[0], projection.scale() * Math.PI - projection.translate()[1]];
33518 this.size(projection.clipExtent()[1]).scale(projection.scale() * 2 * Math.PI).translate(projection.translate());
33519 var tiles = tiler();
33520 var ts = tiles.scale;
33521 return tiles.map(function (tile) {
33522 if (_skipNullIsland && nearNullIsland(tile)) {
33526 var x = tile[0] * ts - origin[0];
33527 var y = tile[1] * ts - origin[1];
33529 id: tile.toString(),
33531 extent: geoExtent(projection.invert([x, y + ts]), projection.invert([x + ts, y]))
33533 }).filter(Boolean);
33536 * getGeoJSON() returns a FeatureCollection for debugging tiles
33540 tiler.getGeoJSON = function (projection) {
33541 var features = tiler.getTiles(projection).map(function (tile) {
33550 coordinates: [tile.extent.polygon()]
33555 type: 'FeatureCollection',
33560 tiler.tileSize = function (val) {
33561 if (!arguments.length) return _tileSize;
33566 tiler.zoomExtent = function (val) {
33567 if (!arguments.length) return _zoomExtent;
33572 tiler.size = function (val) {
33573 if (!arguments.length) return _size;
33578 tiler.scale = function (val) {
33579 if (!arguments.length) return _scale;
33584 tiler.translate = function (val) {
33585 if (!arguments.length) return _translate;
33588 }; // number to extend the rows/columns beyond those covering the viewport
33591 tiler.margin = function (val) {
33592 if (!arguments.length) return _margin;
33597 tiler.skipNullIsland = function (val) {
33598 if (!arguments.length) return _skipNullIsland;
33599 _skipNullIsland = val;
33606 function utilTriggerEvent(target, type) {
33607 target.each(function () {
33608 var evt = document.createEvent('HTMLEvents');
33609 evt.initEvent(type, true, true);
33610 this.dispatchEvent(evt);
33614 var _mainLocations = coreLocations(); // singleton
33615 // `coreLocations` maintains an internal index of all the boundaries/geofences used by iD.
33616 // It's used by presets, community index, background imagery, to know where in the world these things are valid.
33617 // These geofences should be defined by `locationSet` objects:
33619 // let locationSet = {
33620 // include: [ Array of locations ],
33621 // exclude: [ Array of locations ]
33624 // For more info see the location-conflation and country-coder projects, see:
33625 // https://github.com/ideditor/location-conflation
33626 // https://github.com/ideditor/country-coder
33629 function coreLocations() {
33631 var _resolvedFeatures = {}; // cache of *resolved* locationSet features
33633 var _loco = new _default(); // instance of a location-conflation resolver
33636 var _wp; // instance of a which-polygon index
33637 // pre-resolve the worldwide locationSet
33645 resolveLocationSet(world);
33649 var _deferred = new Set();
33651 var _inProcess; // Returns a Promise to process the queue
33654 function processQueue() {
33655 if (!_queue.length) return Promise.resolve(); // console.log(`queue length ${_queue.length}`);
33657 var chunk = _queue.pop();
33659 return new Promise(function (resolvePromise) {
33660 var handle = window.requestIdleCallback(function () {
33661 _deferred["delete"](handle); // const t0 = performance.now();
33664 chunk.forEach(resolveLocationSet); // const t1 = performance.now();
33665 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
33670 _deferred.add(handle);
33671 }).then(function () {
33672 return processQueue();
33674 } // Pass an Object with a `locationSet` property,
33675 // Performs the locationSet resolution, caches the result, and sets a `locationSetID` property on the object.
33678 function resolveLocationSet(obj) {
33679 if (obj.locationSetID) return; // work was done already
33682 var locationSet = obj.locationSet;
33684 if (!locationSet) {
33685 throw new Error('object missing locationSet property');
33688 if (!locationSet.include) {
33689 // missing `include`, default to worldwide include
33690 locationSet.include = ['Q2']; // https://github.com/openstreetmap/iD/pull/8305#discussion_r662344647
33693 var resolved = _loco.resolveLocationSet(locationSet);
33695 var locationSetID = resolved.id;
33696 obj.locationSetID = locationSetID;
33698 if (!resolved.feature.geometry.coordinates.length || !resolved.feature.properties.area) {
33699 throw new Error("locationSet ".concat(locationSetID, " resolves to an empty feature."));
33702 if (!_resolvedFeatures[locationSetID]) {
33703 // First time seeing this locationSet feature
33704 var feature = JSON.parse(JSON.stringify(resolved.feature)); // deep clone
33706 feature.id = locationSetID; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
33708 feature.properties.id = locationSetID;
33709 _resolvedFeatures[locationSetID] = feature; // insert into cache
33712 obj.locationSet = {
33714 }; // default worldwide
33716 obj.locationSetID = '+[Q2]';
33718 } // Rebuilds the whichPolygon index with whatever features have been resolved.
33721 function rebuildIndex() {
33722 _wp = whichPolygon_1({
33723 features: Object.values(_resolvedFeatures)
33726 // `mergeCustomGeoJSON`
33727 // Accepts an FeatureCollection-like object containing custom locations
33728 // Each feature must have a filename-like `id`, for example: `something.geojson`
33731 // "type": "FeatureCollection"
33734 // "type": "Feature",
33735 // "id": "philly_metro.geojson",
33736 // "properties": { … },
33737 // "geometry": { … }
33744 _this.mergeCustomGeoJSON = function (fc) {
33745 if (fc && fc.type === 'FeatureCollection' && Array.isArray(fc.features)) {
33746 fc.features.forEach(function (feature) {
33747 feature.properties = feature.properties || {};
33748 var props = feature.properties; // Get `id` from either `id` or `properties`
33750 var id = feature.id || props.id;
33751 if (!id || !/^\S+\.geojson$/i.test(id)) return; // Ensure `id` exists and is lowercase
33753 id = id.toLowerCase();
33755 props.id = id; // Ensure `area` property exists
33758 var area = geojsonArea.geometry(feature.geometry) / 1e6; // m² to km²
33760 props.area = Number(area.toFixed(2));
33763 _loco._cache[id] = feature;
33767 // `mergeLocationSets`
33768 // Accepts an Array of Objects containing `locationSet` properties.
33769 // The locationSets will be resolved and indexed in the background.
33771 // { id: 'preset1', locationSet: {…} },
33772 // { id: 'preset2', locationSet: {…} },
33773 // { id: 'preset3', locationSet: {…} },
33776 // After resolving and indexing, the Objects will be decorated with a
33777 // `locationSetID` property.
33779 // { id: 'preset1', locationSet: {…}, locationSetID: '+[Q2]' },
33780 // { id: 'preset2', locationSet: {…}, locationSetID: '+[Q30]' },
33781 // { id: 'preset3', locationSet: {…}, locationSetID: '+[Q2]' },
33785 // Returns a Promise fulfilled when the resolving/indexing has been completed
33786 // This will take some seconds but happen in the background during browser idle time.
33790 _this.mergeLocationSets = function (objects) {
33791 if (!Array.isArray(objects)) return Promise.reject('nothing to do'); // Resolve all locationSets -> geojson, processing data in chunks
33793 // Because this will happen during idle callbacks, we want to choose a chunk size
33794 // that won't make the browser stutter too badly. LocationSets that are a simple
33795 // country coder include will resolve instantly, but ones that involve complex
33796 // include/exclude operations will take some milliseconds longer.
33798 // Some discussion and performance results on these tickets:
33799 // https://github.com/ideditor/location-conflation/issues/26
33800 // https://github.com/osmlab/name-suggestion-index/issues/4784#issuecomment-742003434
33802 _queue = _queue.concat(utilArrayChunk(objects, 200));
33805 _inProcess = processQueue().then(function () {
33815 // Returns a locationSetID for a given locationSet (fallback to `+[Q2]`, world)
33816 // (The locationset doesn't necessarily need to be resolved to compute its `id`)
33819 // `locationSet`: A locationSet, e.g. `{ include: ['us'] }`
33821 // The locationSetID, e.g. `+[Q30]`
33825 _this.locationSetID = function (locationSet) {
33829 locationSetID = _loco.validateLocationSet(locationSet).id;
33831 locationSetID = '+[Q2]'; // the world
33834 return locationSetID;
33837 // Returns the resolved GeoJSON feature for a given locationSetID (fallback to 'world')
33840 // `locationSetID`: id of the form like `+[Q30]` (United States)
33842 // A GeoJSON feature:
33844 // type: 'Feature',
33846 // properties: { id: '+[Q30]', area: 21817019.17, … },
33851 _this.feature = function (locationSetID) {
33852 return _resolvedFeatures[locationSetID] || _resolvedFeatures['+[Q2]'];
33855 // Find all the resolved locationSets valid at the given location.
33856 // Results include the area (in km²) to facilitate sorting.
33859 // `loc`: the [lon,lat] location to query, e.g. `[-74.4813, 40.7967]`
33861 // Object of locationSetIDs to areas (in km²)
33863 // "+[Q2]": 511207893.3958111,
33864 // "+[Q30]": 21817019.17,
33865 // "+[new_jersey.geojson]": 22390.77,
33871 _this.locationsAt = function (loc) {
33873 (_wp(loc, true) || []).forEach(function (prop) {
33874 return result[prop.id] = prop.area;
33879 // Execute a query directly against which-polygon
33880 // https://github.com/mapbox/which-polygon
33883 // `loc`: the [lon,lat] location to query,
33884 // `multi`: `true` to return all results, `false` to return first result
33886 // Array of GeoJSON *properties* for the locationSet features that exist at `loc`
33890 _this.query = function (loc, multi) {
33891 return _wp(loc, multi);
33892 }; // Direct access to the location-conflation resolver
33895 _this.loco = function () {
33897 }; // Direct access to the which-polygon index
33900 _this.wp = function () {
33908 var $findIndex = arrayIteration.findIndex;
33909 var addToUnscopables = addToUnscopables$5;
33911 var FIND_INDEX = 'findIndex';
33912 var SKIPS_HOLES = true;
33914 // Shouldn't skip holes
33915 if (FIND_INDEX in []) Array(1)[FIND_INDEX](function () { SKIPS_HOLES = false; });
33917 // `Array.prototype.findIndex` method
33918 // https://tc39.es/ecma262/#sec-array.prototype.findindex
33919 $$a({ target: 'Array', proto: true, forced: SKIPS_HOLES }, {
33920 findIndex: function findIndex(callbackfn /* , that = undefined */) {
33921 return $findIndex(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined);
33925 // https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
33926 addToUnscopables(FIND_INDEX);
33928 var isRegExp = isRegexp;
33930 var notARegexp = function (it) {
33931 if (isRegExp(it)) {
33932 throw TypeError("The method doesn't accept regular expressions");
33936 var wellKnownSymbol = wellKnownSymbol$s;
33938 var MATCH = wellKnownSymbol('match');
33940 var correctIsRegexpLogic = function (METHOD_NAME) {
33943 '/./'[METHOD_NAME](regexp);
33946 regexp[MATCH] = false;
33947 return '/./'[METHOD_NAME](regexp);
33948 } catch (error2) { /* empty */ }
33953 var notARegExp$2 = notARegexp;
33954 var requireObjectCoercible$3 = requireObjectCoercible$e;
33955 var correctIsRegExpLogic$2 = correctIsRegexpLogic;
33957 // `String.prototype.includes` method
33958 // https://tc39.es/ecma262/#sec-string.prototype.includes
33959 $$9({ target: 'String', proto: true, forced: !correctIsRegExpLogic$2('includes') }, {
33960 includes: function includes(searchString /* , position = 0 */) {
33961 return !!~String(requireObjectCoercible$3(this))
33962 .indexOf(notARegExp$2(searchString), arguments.length > 1 ? arguments[1] : undefined);
33966 var _mainLocalizer = coreLocalizer(); // singleton
33969 var _t = _mainLocalizer.t;
33970 // coreLocalizer manages language and locale parameters including translated strings
33973 function coreLocalizer() {
33974 var localizer = {};
33975 var _dataLanguages = {}; // `_dataLocales` is an object containing all _supported_ locale codes -> language info.
33976 // * `rtl` - right-to-left or left-to-right text direction
33977 // * `pct` - the percent of strings translated; 1 = 100%, full coverage
33980 // en: { rtl: false, pct: {…} },
33981 // de: { rtl: false, pct: {…} },
33985 var _dataLocales = {}; // `localeStrings` is an object containing all _loaded_ locale codes -> string data.
33987 // en: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33988 // de: { icons: {…}, toolbar: {…}, modes: {…}, operations: {…}, … },
33992 var _localeStrings = {}; // the current locale
33994 var _localeCode = 'en-US'; // `_localeCodes` must contain `_localeCode` first, optionally followed by fallbacks
33996 var _localeCodes = ['en-US', 'en'];
33997 var _languageCode = 'en';
33998 var _textDirection = 'ltr';
33999 var _usesMetric = false;
34000 var _languageNames = {};
34001 var _scriptNames = {}; // getters for the current locale parameters
34003 localizer.localeCode = function () {
34004 return _localeCode;
34007 localizer.localeCodes = function () {
34008 return _localeCodes;
34011 localizer.languageCode = function () {
34012 return _languageCode;
34015 localizer.textDirection = function () {
34016 return _textDirection;
34019 localizer.usesMetric = function () {
34020 return _usesMetric;
34023 localizer.languageNames = function () {
34024 return _languageNames;
34027 localizer.scriptNames = function () {
34028 return _scriptNames;
34029 }; // The client app may want to manually set the locale, regardless of the
34030 // settings provided by the browser
34033 var _preferredLocaleCodes = [];
34035 localizer.preferredLocaleCodes = function (codes) {
34036 if (!arguments.length) return _preferredLocaleCodes;
34038 if (typeof codes === 'string') {
34039 // be generous and accept delimited strings as input
34040 _preferredLocaleCodes = codes.split(/,|;| /gi).filter(Boolean);
34042 _preferredLocaleCodes = codes;
34050 localizer.ensureLoaded = function () {
34051 if (_loadPromise) return _loadPromise;
34052 var filesToFetch = ['languages', // load the list of languages
34053 'locales' // load the list of supported locales
34056 general: 'locales',
34057 tagging: 'https://cdn.jsdelivr.net/npm/@openstreetmap/id-tagging-schema@3/dist/translations'
34059 var fileMap = _mainFileFetcher.fileMap();
34061 for (var scopeId in localeDirs) {
34062 var key = "locales_index_".concat(scopeId);
34064 if (!fileMap[key]) {
34065 fileMap[key] = localeDirs[scopeId] + '/index.min.json';
34068 filesToFetch.push(key);
34071 return _loadPromise = Promise.all(filesToFetch.map(function (key) {
34072 return _mainFileFetcher.get(key);
34073 })).then(function (results) {
34074 _dataLanguages = results[0];
34075 _dataLocales = results[1];
34076 var indexes = results.slice(2);
34078 var requestedLocales = (_preferredLocaleCodes || []).concat(utilDetect().browserLocales) // List of locales preferred by the browser in priority order.
34079 .concat(['en']); // fallback to English since it's the only guaranteed complete language
34082 _localeCodes = localesToUseFrom(requestedLocales);
34083 _localeCode = _localeCodes[0]; // Run iD in the highest-priority locale; the rest are fallbacks
34085 var loadStringsPromises = [];
34086 indexes.forEach(function (index, i) {
34087 // Will always return the index for `en` if nothing else
34088 var fullCoverageIndex = _localeCodes.findIndex(function (locale) {
34089 return index[locale] && index[locale].pct === 1;
34090 }); // We only need to load locales up until we find one with full coverage
34093 _localeCodes.slice(0, fullCoverageIndex + 1).forEach(function (code) {
34094 var scopeId = Object.keys(localeDirs)[i];
34095 var directory = Object.values(localeDirs)[i];
34096 if (index[code]) loadStringsPromises.push(localizer.loadLocale(code, scopeId, directory));
34099 return Promise.all(loadStringsPromises);
34100 }).then(function () {
34101 updateForCurrentLocale();
34102 })["catch"](function (err) {
34103 return console.error(err);
34104 }); // eslint-disable-line
34105 }; // Returns the locales from `requestedLocales` supported by iD that we should use
34108 function localesToUseFrom(requestedLocales) {
34109 var supportedLocales = _dataLocales;
34112 for (var i in requestedLocales) {
34113 var locale = requestedLocales[i];
34114 if (supportedLocales[locale]) toUse.push(locale);
34116 if (locale.includes('-')) {
34117 // Full locale ('es-ES'), add fallback to the base ('es')
34118 var langPart = locale.split('-')[0];
34119 if (supportedLocales[langPart]) toUse.push(langPart);
34121 } // remove duplicates
34124 return utilArrayUniq(toUse);
34127 function updateForCurrentLocale() {
34128 if (!_localeCode) return;
34129 _languageCode = _localeCode.split('-')[0];
34130 var currentData = _dataLocales[_localeCode] || _dataLocales[_languageCode];
34131 var hash = utilStringQs(window.location.hash);
34133 if (hash.rtl === 'true') {
34134 _textDirection = 'rtl';
34135 } else if (hash.rtl === 'false') {
34136 _textDirection = 'ltr';
34138 _textDirection = currentData && currentData.rtl ? 'rtl' : 'ltr';
34141 var locale = _localeCode;
34142 if (locale.toLowerCase() === 'en-us') locale = 'en';
34143 _languageNames = _localeStrings.general[locale].languageNames;
34144 _scriptNames = _localeStrings.general[locale].scriptNames;
34145 _usesMetric = _localeCode.slice(-3).toLowerCase() !== '-us';
34148 // Returns a Promise to load the strings for the requested locale
34151 localizer.loadLocale = function (locale, scopeId, directory) {
34152 // US English is the default
34153 if (locale.toLowerCase() === 'en-us') locale = 'en';
34155 if (_localeStrings[scopeId] && _localeStrings[scopeId][locale]) {
34157 return Promise.resolve(locale);
34160 var fileMap = _mainFileFetcher.fileMap();
34161 var key = "locale_".concat(scopeId, "_").concat(locale);
34163 if (!fileMap[key]) {
34164 fileMap[key] = "".concat(directory, "/").concat(locale, ".min.json");
34167 return _mainFileFetcher.get(key).then(function (d) {
34168 if (!_localeStrings[scopeId]) _localeStrings[scopeId] = {};
34169 _localeStrings[scopeId][locale] = d[locale];
34174 localizer.pluralRule = function (number) {
34175 return pluralRule(number, _localeCode);
34176 }; // Returns the plural rule for the given `number` with the given `localeCode`.
34177 // One of: `zero`, `one`, `two`, `few`, `many`, `other`
34180 function pluralRule(number, localeCode) {
34181 // modern browsers have this functionality built-in
34182 var rules = 'Intl' in window && Intl.PluralRules && new Intl.PluralRules(localeCode);
34185 return rules.select(number);
34186 } // fallback to basic one/other, as in English
34189 if (number === 1) return 'one';
34193 * Try to find that string in `locale` or the current `_localeCode` matching
34194 * the given `stringId`. If no string can be found in the requested locale,
34195 * we'll recurse down all the `_localeCodes` until one is found.
34197 * @param {string} stringId string identifier
34198 * @param {object?} replacements token replacements and default string
34199 * @param {string?} locale locale to use (defaults to currentLocale)
34200 * @return {string?} localized string
34204 localizer.tInfo = function (origStringId, replacements, locale) {
34205 var stringId = origStringId.trim();
34206 var scopeId = 'general';
34208 if (stringId[0] === '_') {
34209 var split = stringId.split('.');
34210 scopeId = split[0].slice(1);
34211 stringId = split.slice(1).join('.');
34214 locale = locale || _localeCode;
34215 var path = stringId.split('.').map(function (s) {
34216 return s.replace(/<TX_DOT>/g, '.');
34218 var stringsKey = locale; // US English is the default
34220 if (stringsKey.toLowerCase() === 'en-us') stringsKey = 'en';
34221 var result = _localeStrings && _localeStrings[scopeId] && _localeStrings[scopeId][stringsKey];
34223 while (result !== undefined && path.length) {
34224 result = result[path.pop()];
34227 if (result !== undefined) {
34228 if (replacements) {
34229 if (_typeof(result) === 'object' && Object.keys(result).length) {
34230 // If plural forms are provided, dig one level deeper based on the
34231 // first numeric token replacement provided.
34232 var number = Object.values(replacements).find(function (value) {
34233 return typeof value === 'number';
34236 if (number !== undefined) {
34237 var rule = pluralRule(number, locale);
34239 if (result[rule]) {
34240 result = result[rule];
34242 // We're pretty sure this should be a plural but no string
34243 // could be found for the given rule. Just pick the first
34244 // string and hope it makes sense.
34245 result = Object.values(result)[0];
34250 if (typeof result === 'string') {
34251 for (var key in replacements) {
34252 var value = replacements[key];
34254 if (typeof value === 'number') {
34255 if (value.toLocaleString) {
34256 // format numbers for the locale
34257 value = value.toLocaleString(locale, {
34260 minimumFractionDigits: 0
34263 value = value.toString();
34267 var token = "{".concat(key, "}");
34268 var regex = new RegExp(token, 'g');
34269 result = result.replace(regex, value);
34274 if (typeof result === 'string') {
34275 // found a localized string!
34281 } // no localized string found...
34282 // attempt to fallback to a lower-priority language
34285 var index = _localeCodes.indexOf(locale);
34287 if (index >= 0 && index < _localeCodes.length - 1) {
34288 // eventually this will be 'en' or another locale with 100% coverage
34289 var fallback = _localeCodes[index + 1];
34290 return localizer.tInfo(origStringId, replacements, fallback);
34293 if (replacements && 'default' in replacements) {
34294 // Fallback to a default value if one is specified in `replacements`
34296 text: replacements["default"],
34301 var missing = "Missing ".concat(locale, " translation: ").concat(origStringId);
34302 if (typeof console !== 'undefined') console.error(missing); // eslint-disable-line
34310 localizer.hasTextForStringId = function (stringId) {
34311 return !!localizer.tInfo(stringId, {
34312 "default": 'nothing found'
34314 }; // Returns only the localized text, discarding the locale info
34317 localizer.t = function (stringId, replacements, locale) {
34318 return localizer.tInfo(stringId, replacements, locale).text;
34319 }; // Returns the localized text wrapped in an HTML element encoding the locale info
34322 localizer.t.html = function (stringId, replacements, locale) {
34323 var info = localizer.tInfo(stringId, replacements, locale); // text may be empty or undefined if `replacements.default` is
34325 return info.text ? localizer.htmlForLocalizedText(info.text, info.locale) : '';
34328 localizer.htmlForLocalizedText = function (text, localeCode) {
34329 return "<span class=\"localized-text\" lang=\"".concat(localeCode || 'unknown', "\">").concat(text, "</span>");
34332 localizer.languageName = function (code, options) {
34333 if (_languageNames[code]) {
34334 // name in locale language
34336 return _languageNames[code];
34337 } // sometimes we only want the local name
34340 if (options && options.localOnly) return null;
34341 var langInfo = _dataLanguages[code];
34344 if (langInfo.nativeName) {
34345 // name in native language
34346 // e.g. "Deutsch (de)"
34347 return localizer.t('translate.language_and_code', {
34348 language: langInfo.nativeName,
34351 } else if (langInfo.base && langInfo.script) {
34352 var base = langInfo.base; // the code of the language this is based on
34354 if (_languageNames[base]) {
34355 // base language name in locale language
34356 var scriptCode = langInfo.script;
34357 var script = _scriptNames[scriptCode] || scriptCode; // e.g. "Serbian (Cyrillic)"
34359 return localizer.t('translate.language_and_code', {
34360 language: _languageNames[base],
34363 } else if (_dataLanguages[base] && _dataLanguages[base].nativeName) {
34364 // e.g. "српски (sr-Cyrl)"
34365 return localizer.t('translate.language_and_code', {
34366 language: _dataLanguages[base].nativeName,
34373 return code; // if not found, use the code
34379 // `presetCollection` is a wrapper around an `Array` of presets `collection`,
34380 // and decorated with some extra methods for searching and matching geometry
34383 function presetCollection(collection) {
34384 var MAXRESULTS = 50;
34387 _this.collection = collection;
34389 _this.item = function (id) {
34390 if (_memo[id]) return _memo[id];
34392 var found = _this.collection.find(function (d) {
34393 return d.id === id;
34396 if (found) _memo[id] = found;
34400 _this.index = function (id) {
34401 return _this.collection.findIndex(function (d) {
34402 return d.id === id;
34406 _this.matchGeometry = function (geometry) {
34407 return presetCollection(_this.collection.filter(function (d) {
34408 return d.matchGeometry(geometry);
34412 _this.matchAllGeometry = function (geometries) {
34413 return presetCollection(_this.collection.filter(function (d) {
34414 return d && d.matchAllGeometry(geometries);
34418 _this.matchAnyGeometry = function (geometries) {
34419 return presetCollection(_this.collection.filter(function (d) {
34420 return geometries.some(function (geom) {
34421 return d.matchGeometry(geom);
34426 _this.fallback = function (geometry) {
34428 if (id === 'vertex') id = 'point';
34429 return _this.item(id);
34432 _this.search = function (value, geometry, loc) {
34433 if (!value) return _this; // don't remove diacritical characters since we're assuming the user is being intentional
34435 value = value.toLowerCase().trim(); // match at name beginning or just after a space (e.g. "office" -> match "Law Office")
34437 function leading(a) {
34438 var index = a.indexOf(value);
34439 return index === 0 || a[index - 1] === ' ';
34440 } // match at name beginning only
34443 function leadingStrict(a) {
34444 var index = a.indexOf(value);
34445 return index === 0;
34448 function sortPresets(nameProp) {
34449 return function sortNames(a, b) {
34450 var aCompare = a[nameProp]();
34451 var bCompare = b[nameProp](); // priority if search string matches preset name exactly - #4325
34453 if (value === aCompare) return -1;
34454 if (value === bCompare) return 1; // priority for higher matchScore
34456 var i = b.originalScore - a.originalScore;
34457 if (i !== 0) return i; // priority if search string appears earlier in preset name
34459 i = aCompare.indexOf(value) - bCompare.indexOf(value);
34460 if (i !== 0) return i; // priority for shorter preset names
34462 return aCompare.length - bCompare.length;
34466 var pool = _this.collection;
34468 if (Array.isArray(loc)) {
34469 var validLocations = _mainLocations.locationsAt(loc);
34470 pool = pool.filter(function (a) {
34471 return !a.locationSetID || validLocations[a.locationSetID];
34475 var searchable = pool.filter(function (a) {
34476 return a.searchable !== false && a.suggestion !== true;
34478 var suggestions = pool.filter(function (a) {
34479 return a.suggestion === true;
34480 }); // matches value to preset.name
34482 var leadingNames = searchable.filter(function (a) {
34483 return leading(a.searchName());
34484 }).sort(sortPresets('searchName')); // matches value to preset suggestion name
34486 var leadingSuggestions = suggestions.filter(function (a) {
34487 return leadingStrict(a.searchName());
34488 }).sort(sortPresets('searchName'));
34489 var leadingNamesStripped = searchable.filter(function (a) {
34490 return leading(a.searchNameStripped());
34491 }).sort(sortPresets('searchNameStripped'));
34492 var leadingSuggestionsStripped = suggestions.filter(function (a) {
34493 return leadingStrict(a.searchNameStripped());
34494 }).sort(sortPresets('searchNameStripped')); // matches value to preset.terms values
34496 var leadingTerms = searchable.filter(function (a) {
34497 return (a.terms() || []).some(leading);
34499 var leadingSuggestionTerms = suggestions.filter(function (a) {
34500 return (a.terms() || []).some(leading);
34501 }); // matches value to preset.tags values
34503 var leadingTagValues = searchable.filter(function (a) {
34504 return Object.values(a.tags || {}).filter(function (val) {
34505 return val !== '*';
34507 }); // finds close matches to value in preset.name
34509 var similarName = searchable.map(function (a) {
34512 dist: utilEditDistance(value, a.searchName())
34514 }).filter(function (a) {
34515 return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 3;
34516 }).sort(function (a, b) {
34517 return a.dist - b.dist;
34518 }).map(function (a) {
34520 }); // finds close matches to value to preset suggestion name
34522 var similarSuggestions = suggestions.map(function (a) {
34525 dist: utilEditDistance(value, a.searchName())
34527 }).filter(function (a) {
34528 return a.dist + Math.min(value.length - a.preset.searchName().length, 0) < 1;
34529 }).sort(function (a, b) {
34530 return a.dist - b.dist;
34531 }).map(function (a) {
34533 }); // finds close matches to value in preset.terms
34535 var similarTerms = searchable.filter(function (a) {
34536 return (a.terms() || []).some(function (b) {
34537 return utilEditDistance(value, b) + Math.min(value.length - b.length, 0) < 3;
34540 var results = leadingNames.concat(leadingSuggestions, leadingNamesStripped, leadingSuggestionsStripped, leadingTerms, leadingSuggestionTerms, leadingTagValues, similarName, similarSuggestions, similarTerms).slice(0, MAXRESULTS - 1);
34543 if (typeof geometry === 'string') {
34544 results.push(_this.fallback(geometry));
34546 geometry.forEach(function (geom) {
34547 return results.push(_this.fallback(geom));
34552 return presetCollection(utilArrayUniq(results));
34558 // `presetCategory` builds a `presetCollection` of member presets,
34559 // decorated with some extra methods for searching and matching geometry
34562 function presetCategory(categoryID, category, allPresets) {
34563 var _this = Object.assign({}, category); // shallow copy
34566 var _searchName; // cache
34569 var _searchNameStripped; // cache
34572 _this.id = categoryID;
34573 _this.members = presetCollection((category.members || []).map(function (presetID) {
34574 return allPresets[presetID];
34575 }).filter(Boolean));
34576 _this.geometry = _this.members.collection.reduce(function (acc, preset) {
34577 for (var i in preset.geometry) {
34578 var geometry = preset.geometry[i];
34580 if (acc.indexOf(geometry) === -1) {
34581 acc.push(geometry);
34588 _this.matchGeometry = function (geom) {
34589 return _this.geometry.indexOf(geom) >= 0;
34592 _this.matchAllGeometry = function (geometries) {
34593 return _this.members.collection.some(function (preset) {
34594 return preset.matchAllGeometry(geometries);
34598 _this.matchScore = function () {
34602 _this.name = function () {
34603 return _t("_tagging.presets.categories.".concat(categoryID, ".name"), {
34604 'default': categoryID
34608 _this.nameLabel = function () {
34609 return _t.html("_tagging.presets.categories.".concat(categoryID, ".name"), {
34610 'default': categoryID
34614 _this.terms = function () {
34618 _this.searchName = function () {
34619 if (!_searchName) {
34620 _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
34623 return _searchName;
34626 _this.searchNameStripped = function () {
34627 if (!_searchNameStripped) {
34628 _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
34630 if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
34632 _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
34635 return _searchNameStripped;
34641 // `presetField` decorates a given `field` Object
34642 // with some extra methods for searching and matching geometry
34645 function presetField(fieldID, field) {
34646 var _this = Object.assign({}, field); // shallow copy
34649 _this.id = fieldID; // for use in classes, element ids, css selectors
34651 _this.safeid = utilSafeClassName(fieldID);
34653 _this.matchGeometry = function (geom) {
34654 return !_this.geometry || _this.geometry.indexOf(geom) !== -1;
34657 _this.matchAllGeometry = function (geometries) {
34658 return !_this.geometry || geometries.every(function (geom) {
34659 return _this.geometry.indexOf(geom) !== -1;
34663 _this.t = function (scope, options) {
34664 return _t("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
34667 _this.t.html = function (scope, options) {
34668 return _t.html("_tagging.presets.fields.".concat(fieldID, ".").concat(scope), options);
34671 _this.hasTextForStringId = function (scope) {
34672 return _mainLocalizer.hasTextForStringId("_tagging.presets.fields.".concat(fieldID, ".").concat(scope));
34675 _this.title = function () {
34676 return _this.overrideLabel || _this.t('label', {
34681 _this.label = function () {
34682 return _this.overrideLabel || _this.t.html('label', {
34687 var _placeholder = _this.placeholder;
34689 _this.placeholder = function () {
34690 return _this.t('placeholder', {
34691 'default': _placeholder
34695 _this.originalTerms = (_this.terms || []).join();
34697 _this.terms = function () {
34698 return _this.t('terms', {
34699 'default': _this.originalTerms
34700 }).toLowerCase().trim().split(/\s*,+\s*/);
34703 _this.increment = _this.type === 'number' ? _this.increment || 1 : undefined;
34708 var lastIndexOf = arrayLastIndexOf;
34710 // `Array.prototype.lastIndexOf` method
34711 // https://tc39.es/ecma262/#sec-array.prototype.lastindexof
34712 // eslint-disable-next-line es/no-array-prototype-lastindexof -- required for testing
34713 $$8({ target: 'Array', proto: true, forced: lastIndexOf !== [].lastIndexOf }, {
34714 lastIndexOf: lastIndexOf
34717 // `presetPreset` decorates a given `preset` Object
34718 // with some extra methods for searching and matching geometry
34721 function presetPreset(presetID, preset, addable, allFields, allPresets) {
34722 allFields = allFields || {};
34723 allPresets = allPresets || {};
34725 var _this = Object.assign({}, preset); // shallow copy
34728 var _addable = addable || false;
34730 var _resolvedFields; // cache
34733 var _resolvedMoreFields; // cache
34736 var _searchName; // cache
34739 var _searchNameStripped; // cache
34742 _this.id = presetID;
34743 _this.safeid = utilSafeClassName(presetID); // for use in css classes, selectors, element ids
34745 _this.originalTerms = (_this.terms || []).join();
34746 _this.originalName = _this.name || '';
34747 _this.originalScore = _this.matchScore || 1;
34748 _this.originalReference = _this.reference || {};
34749 _this.originalFields = _this.fields || [];
34750 _this.originalMoreFields = _this.moreFields || [];
34752 _this.fields = function () {
34753 return _resolvedFields || (_resolvedFields = resolve('fields'));
34756 _this.moreFields = function () {
34757 return _resolvedMoreFields || (_resolvedMoreFields = resolve('moreFields'));
34760 _this.resetFields = function () {
34761 return _resolvedFields = _resolvedMoreFields = null;
34764 _this.tags = _this.tags || {};
34765 _this.addTags = _this.addTags || _this.tags;
34766 _this.removeTags = _this.removeTags || _this.addTags;
34767 _this.geometry = _this.geometry || [];
34769 _this.matchGeometry = function (geom) {
34770 return _this.geometry.indexOf(geom) >= 0;
34773 _this.matchAllGeometry = function (geoms) {
34774 return geoms.every(_this.matchGeometry);
34777 _this.matchScore = function (entityTags) {
34778 var tags = _this.tags;
34780 var score = 0; // match on tags
34782 for (var k in tags) {
34785 if (entityTags[k] === tags[k]) {
34786 score += _this.originalScore;
34787 } else if (tags[k] === '*' && k in entityTags) {
34788 score += _this.originalScore / 2;
34792 } // boost score for additional matches in addTags - #6802
34795 var addTags = _this.addTags;
34797 for (var _k in addTags) {
34798 if (!seen[_k] && entityTags[_k] === addTags[_k]) {
34799 score += _this.originalScore;
34806 _this.t = function (scope, options) {
34807 var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
34808 return _t(textID, options);
34811 _this.t.html = function (scope, options) {
34812 var textID = "_tagging.presets.presets.".concat(presetID, ".").concat(scope);
34813 return _t.html(textID, options);
34816 _this.name = function () {
34817 return _this.t('name', {
34818 'default': _this.originalName
34822 _this.nameLabel = function () {
34823 return _this.t.html('name', {
34824 'default': _this.originalName
34828 _this.subtitle = function () {
34829 if (_this.suggestion) {
34830 var path = presetID.split('/');
34831 path.pop(); // remove brand name
34833 return _t('_tagging.presets.presets.' + path.join('/') + '.name');
34839 _this.subtitleLabel = function () {
34840 if (_this.suggestion) {
34841 var path = presetID.split('/');
34842 path.pop(); // remove brand name
34844 return _t.html('_tagging.presets.presets.' + path.join('/') + '.name');
34850 _this.terms = function () {
34851 return _this.t('terms', {
34852 'default': _this.originalTerms
34853 }).toLowerCase().trim().split(/\s*,+\s*/);
34856 _this.searchName = function () {
34857 if (!_searchName) {
34858 _searchName = (_this.suggestion ? _this.originalName : _this.name()).toLowerCase();
34861 return _searchName;
34864 _this.searchNameStripped = function () {
34865 if (!_searchNameStripped) {
34866 _searchNameStripped = _this.searchName(); // split combined diacritical characters into their parts
34868 if (_searchNameStripped.normalize) _searchNameStripped = _searchNameStripped.normalize('NFD'); // remove diacritics
34870 _searchNameStripped = _searchNameStripped.replace(/[\u0300-\u036f]/g, '');
34873 return _searchNameStripped;
34876 _this.isFallback = function () {
34877 var tagCount = Object.keys(_this.tags).length;
34878 return tagCount === 0 || tagCount === 1 && _this.tags.hasOwnProperty('area');
34881 _this.addable = function (val) {
34882 if (!arguments.length) return _addable;
34887 _this.reference = function () {
34888 // Lookup documentation on Wikidata...
34889 var qid = _this.tags.wikidata || _this.tags['flag:wikidata'] || _this.tags['brand:wikidata'] || _this.tags['network:wikidata'] || _this.tags['operator:wikidata'];
34895 } // Lookup documentation on OSM Wikibase...
34898 var key = _this.originalReference.key || Object.keys(utilObjectOmit(_this.tags, 'name'))[0];
34899 var value = _this.originalReference.value || _this.tags[key];
34901 if (value === '*') {
34913 _this.unsetTags = function (tags, geometry, ignoringKeys, skipFieldDefaults) {
34914 // allow manually keeping some tags
34915 var removeTags = ignoringKeys ? utilObjectOmit(_this.removeTags, ignoringKeys) : _this.removeTags;
34916 tags = utilObjectOmit(tags, Object.keys(removeTags));
34918 if (geometry && !skipFieldDefaults) {
34919 _this.fields().forEach(function (field) {
34920 if (field.matchGeometry(geometry) && field.key && field["default"] === tags[field.key]) {
34921 delete tags[field.key];
34930 _this.setTags = function (tags, geometry, skipFieldDefaults) {
34931 var addTags = _this.addTags;
34932 tags = Object.assign({}, tags); // shallow copy
34934 for (var k in addTags) {
34935 if (addTags[k] === '*') {
34936 // if this tag is ancillary, don't override an existing value since any value is okay
34937 if (_this.tags[k] || !tags[k] || tags[k] === 'no') {
34941 tags[k] = addTags[k];
34943 } // Add area=yes if necessary.
34944 // This is necessary if the geometry is already an area (e.g. user drew an area) AND any of:
34945 // 1. chosen preset could be either an area or a line (`barrier=city_wall`)
34946 // 2. chosen preset doesn't have a key in osmAreaKeys (`railway=station`)
34949 if (!addTags.hasOwnProperty('area')) {
34952 if (geometry === 'area') {
34953 var needsAreaTag = true;
34955 if (_this.geometry.indexOf('line') === -1) {
34956 for (var _k2 in addTags) {
34957 if (_k2 in osmAreaKeys) {
34958 needsAreaTag = false;
34964 if (needsAreaTag) {
34970 if (geometry && !skipFieldDefaults) {
34971 _this.fields().forEach(function (field) {
34972 if (field.matchGeometry(geometry) && field.key && !tags[field.key] && field["default"]) {
34973 tags[field.key] = field["default"];
34979 }; // For a preset without fields, use the fields of the parent preset.
34980 // Replace {preset} placeholders with the fields of the specified presets.
34983 function resolve(which) {
34984 var fieldIDs = which === 'fields' ? _this.originalFields : _this.originalMoreFields;
34986 fieldIDs.forEach(function (fieldID) {
34987 var match = fieldID.match(/\{(.*)\}/);
34989 if (match !== null) {
34990 // a presetID wrapped in braces {}
34991 resolved = resolved.concat(inheritFields(match[1], which));
34992 } else if (allFields[fieldID]) {
34993 // a normal fieldID
34994 resolved.push(allFields[fieldID]);
34996 console.log("Cannot resolve \"".concat(fieldID, "\" found in ").concat(_this.id, ".").concat(which)); // eslint-disable-line no-console
34998 }); // no fields resolved, so use the parent's if possible
35000 if (!resolved.length) {
35001 var endIndex = _this.id.lastIndexOf('/');
35003 var parentID = endIndex && _this.id.substring(0, endIndex);
35006 resolved = inheritFields(parentID, which);
35010 return utilArrayUniq(resolved); // returns an array of fields to inherit from the given presetID, if found
35012 function inheritFields(presetID, which) {
35013 var parent = allPresets[presetID];
35014 if (!parent) return [];
35016 if (which === 'fields') {
35017 return parent.fields().filter(shouldInherit);
35018 } else if (which === 'moreFields') {
35019 return parent.moreFields();
35023 } // Skip `fields` for the keys which define the preset.
35024 // These are usually `typeCombo` fields like `shop=*`
35027 function shouldInherit(f) {
35028 if (f.key && _this.tags[f.key] !== undefined && // inherit anyway if multiple values are allowed or just a checkbox
35029 f.type !== 'multiCombo' && f.type !== 'semiCombo' && f.type !== 'manyCombo' && f.type !== 'check') return false;
35037 var _mainPresetIndex = presetIndex(); // singleton
35038 // `presetIndex` wraps a `presetCollection`
35039 // with methods for loading new data and returning defaults
35042 function presetIndex() {
35043 var dispatch = dispatch$8('favoritePreset', 'recentsChange');
35044 var MAXRECENTS = 30; // seed the preset lists with geometry fallbacks
35046 var POINT = presetPreset('point', {
35049 geometry: ['point', 'vertex'],
35052 var LINE = presetPreset('line', {
35055 geometry: ['line'],
35058 var AREA = presetPreset('area', {
35063 geometry: ['area'],
35066 var RELATION = presetPreset('relation', {
35069 geometry: ['relation'],
35073 var _this = presetCollection([POINT, LINE, AREA, RELATION]);
35082 point: presetCollection([POINT]),
35083 vertex: presetCollection([POINT]),
35084 line: presetCollection([LINE]),
35085 area: presetCollection([AREA]),
35086 relation: presetCollection([RELATION])
35089 var _categories = {};
35090 var _universal = [];
35091 var _addablePresetIDs = null; // Set of preset IDs that the user can add
35095 var _favorites; // Index of presets by (geometry, tag key).
35098 var _geometryIndex = {
35108 _this.ensureLoaded = function () {
35109 if (_loadPromise) return _loadPromise;
35110 return _loadPromise = Promise.all([_mainFileFetcher.get('preset_categories'), _mainFileFetcher.get('preset_defaults'), _mainFileFetcher.get('preset_presets'), _mainFileFetcher.get('preset_fields')]).then(function (vals) {
35112 categories: vals[0],
35118 osmSetAreaKeys(_this.areaKeys());
35119 osmSetPointTags(_this.pointTags());
35120 osmSetVertexTags(_this.vertexTags());
35122 }; // `merge` accepts an object containing new preset data (all properties optional):
35128 // featureCollection: {}
35132 _this.merge = function (d) {
35133 var newLocationSets = []; // Merge Fields
35136 Object.keys(d.fields).forEach(function (fieldID) {
35137 var f = d.fields[fieldID];
35141 f = presetField(fieldID, f);
35142 if (f.locationSet) newLocationSets.push(f);
35143 _fields[fieldID] = f;
35146 delete _fields[fieldID];
35153 Object.keys(d.presets).forEach(function (presetID) {
35154 var p = d.presets[presetID];
35158 var isAddable = !_addablePresetIDs || _addablePresetIDs.has(presetID);
35160 p = presetPreset(presetID, p, isAddable, _fields, _presets);
35161 if (p.locationSet) newLocationSets.push(p);
35162 _presets[presetID] = p;
35164 // remove (but not if it's a fallback)
35165 var existing = _presets[presetID];
35167 if (existing && !existing.isFallback()) {
35168 delete _presets[presetID];
35172 } // Merge Categories
35175 if (d.categories) {
35176 Object.keys(d.categories).forEach(function (categoryID) {
35177 var c = d.categories[categoryID];
35181 c = presetCategory(categoryID, c, _presets);
35182 if (c.locationSet) newLocationSets.push(c);
35183 _categories[categoryID] = c;
35186 delete _categories[categoryID];
35189 } // Rebuild _this.collection after changing presets and categories
35192 _this.collection = Object.values(_presets).concat(Object.values(_categories)); // Merge Defaults
35195 Object.keys(d.defaults).forEach(function (geometry) {
35196 var def = d.defaults[geometry];
35198 if (Array.isArray(def)) {
35200 _defaults[geometry] = presetCollection(def.map(function (id) {
35201 return _presets[id] || _categories[id];
35202 }).filter(Boolean));
35205 delete _defaults[geometry];
35208 } // Rebuild universal fields array
35211 _universal = Object.values(_fields).filter(function (field) {
35212 return field.universal;
35213 }); // Reset all the preset fields - they'll need to be resolved again
35215 Object.values(_presets).forEach(function (preset) {
35216 return preset.resetFields();
35217 }); // Rebuild geometry index
35227 _this.collection.forEach(function (preset) {
35228 (preset.geometry || []).forEach(function (geometry) {
35229 var g = _geometryIndex[geometry];
35231 for (var key in preset.tags) {
35232 g[key] = g[key] || {};
35233 var value = preset.tags[key];
35234 (g[key][value] = g[key][value] || []).push(preset);
35237 }); // Merge Custom Features
35240 if (d.featureCollection && Array.isArray(d.featureCollection.features)) {
35241 _mainLocations.mergeCustomGeoJSON(d.featureCollection);
35242 } // Resolve all locationSet features.
35245 if (newLocationSets.length) {
35246 _mainLocations.mergeLocationSets(newLocationSets);
35252 _this.match = function (entity, resolver) {
35253 return resolver["transient"](entity, 'presetMatch', function () {
35254 var geometry = entity.geometry(resolver); // Treat entities on addr:interpolation lines as points, not vertices - #3241
35256 if (geometry === 'vertex' && entity.isOnAddressLine(resolver)) {
35257 geometry = 'point';
35260 var entityExtent = entity.extent(resolver);
35261 return _this.matchTags(entity.tags, geometry, entityExtent.center());
35265 _this.matchTags = function (tags, geometry, loc) {
35266 var keyIndex = _geometryIndex[geometry];
35267 var bestScore = -1;
35269 var matchCandidates = [];
35271 for (var k in tags) {
35272 var indexMatches = [];
35273 var valueIndex = keyIndex[k];
35274 if (!valueIndex) continue;
35275 var keyValueMatches = valueIndex[tags[k]];
35276 if (keyValueMatches) indexMatches.push.apply(indexMatches, _toConsumableArray(keyValueMatches));
35277 var keyStarMatches = valueIndex['*'];
35278 if (keyStarMatches) indexMatches.push.apply(indexMatches, _toConsumableArray(keyStarMatches));
35279 if (indexMatches.length === 0) continue;
35281 for (var i = 0; i < indexMatches.length; i++) {
35282 var candidate = indexMatches[i];
35283 var score = candidate.matchScore(tags);
35285 if (score === -1) {
35289 matchCandidates.push({
35291 candidate: candidate
35294 if (score > bestScore) {
35296 bestMatch = candidate;
35301 if (bestMatch && bestMatch.locationSetID && bestMatch.locationSetID !== '+[Q2]' && Array.isArray(loc)) {
35302 var validLocations = _mainLocations.locationsAt(loc);
35304 if (!validLocations[bestMatch.locationSetID]) {
35305 matchCandidates.sort(function (a, b) {
35306 return a.score < b.score ? 1 : -1;
35309 for (var _i = 0; _i < matchCandidates.length; _i++) {
35310 var candidateScore = matchCandidates[_i];
35312 if (!candidateScore.candidate.locationSetID || validLocations[candidateScore.candidate.locationSetID]) {
35313 bestMatch = candidateScore.candidate;
35314 bestScore = candidateScore.score;
35319 } // If any part of an address is present, allow fallback to "Address" preset - #4353
35322 if (!bestMatch || bestMatch.isFallback()) {
35323 for (var _k in tags) {
35324 if (/^addr:/.test(_k) && keyIndex['addr:*'] && keyIndex['addr:*']['*']) {
35325 bestMatch = keyIndex['addr:*']['*'][0];
35331 return bestMatch || _this.fallback(geometry);
35334 _this.allowsVertex = function (entity, resolver) {
35335 if (entity.type !== 'node') return false;
35336 if (Object.keys(entity.tags).length === 0) return true;
35337 return resolver["transient"](entity, 'vertexMatch', function () {
35338 // address lines allow vertices to act as standalone points
35339 if (entity.isOnAddressLine(resolver)) return true;
35340 var geometries = osmNodeGeometriesForTags(entity.tags);
35341 if (geometries.vertex) return true;
35342 if (geometries.point) return false; // allow vertices for unspecified points
35346 }; // Because of the open nature of tagging, iD will never have a complete
35347 // list of tags used in OSM, so we want it to have logic like "assume
35348 // that a closed way with an amenity tag is an area, unless the amenity
35349 // is one of these specific types". This function computes a structure
35350 // that allows testing of such conditions, based on the presets designated
35351 // as as supporting (or not supporting) the area geometry.
35353 // The returned object L is a keeplist/discardlist of tags. A closed way
35354 // with a tag (k, v) is considered to be an area if `k in L && !(v in L[k])`
35355 // (see `Way#isArea()`). In other words, the keys of L form the keeplist,
35356 // and the subkeys form the discardlist.
35359 _this.areaKeys = function () {
35360 // The ignore list is for keys that imply lines. (We always add `area=yes` for exceptions)
35361 var ignore = ['barrier', 'highway', 'footway', 'railway', 'junction', 'type'];
35362 var areaKeys = {}; // ignore name-suggestion-index and deprecated presets
35364 var presets = _this.collection.filter(function (p) {
35365 return !p.suggestion && !p.replacement;
35369 presets.forEach(function (p) {
35370 var keys = p.tags && Object.keys(p.tags);
35371 var key = keys && keys.length && keys[0]; // pick the first tag
35374 if (ignore.indexOf(key) !== -1) return;
35376 if (p.geometry.indexOf('area') !== -1) {
35377 // probably an area..
35378 areaKeys[key] = areaKeys[key] || {};
35382 presets.forEach(function (p) {
35385 for (key in p.addTags) {
35386 // examine all addTags to get a better sense of what can be tagged on lines - #6800
35387 var value = p.addTags[key];
35389 if (key in areaKeys && // probably an area...
35390 p.geometry.indexOf('line') !== -1 && // but sometimes a line
35392 areaKeys[key][value] = true;
35399 _this.pointTags = function () {
35400 return _this.collection.reduce(function (pointTags, d) {
35401 // ignore name-suggestion-index, deprecated, and generic presets
35402 if (d.suggestion || d.replacement || d.searchable === false) return pointTags; // only care about the primary tag
35404 var keys = d.tags && Object.keys(d.tags);
35405 var key = keys && keys.length && keys[0]; // pick the first tag
35407 if (!key) return pointTags; // if this can be a point
35409 if (d.geometry.indexOf('point') !== -1) {
35410 pointTags[key] = pointTags[key] || {};
35411 pointTags[key][d.tags[key]] = true;
35418 _this.vertexTags = function () {
35419 return _this.collection.reduce(function (vertexTags, d) {
35420 // ignore name-suggestion-index, deprecated, and generic presets
35421 if (d.suggestion || d.replacement || d.searchable === false) return vertexTags; // only care about the primary tag
35423 var keys = d.tags && Object.keys(d.tags);
35424 var key = keys && keys.length && keys[0]; // pick the first tag
35426 if (!key) return vertexTags; // if this can be a vertex
35428 if (d.geometry.indexOf('vertex') !== -1) {
35429 vertexTags[key] = vertexTags[key] || {};
35430 vertexTags[key][d.tags[key]] = true;
35437 _this.field = function (id) {
35438 return _fields[id];
35441 _this.universal = function () {
35445 _this.defaults = function (geometry, n, startWithRecents, loc) {
35448 if (startWithRecents) {
35449 recents = _this.recent().matchGeometry(geometry).collection.slice(0, 4);
35454 if (_addablePresetIDs) {
35455 defaults = Array.from(_addablePresetIDs).map(function (id) {
35456 var preset = _this.item(id);
35458 if (preset && preset.matchGeometry(geometry)) return preset;
35460 }).filter(Boolean);
35462 defaults = _defaults[geometry].collection.concat(_this.fallback(geometry));
35465 var result = presetCollection(utilArrayUniq(recents.concat(defaults)).slice(0, n - 1));
35467 if (Array.isArray(loc)) {
35468 var validLocations = _mainLocations.locationsAt(loc);
35469 result.collection = result.collection.filter(function (a) {
35470 return !a.locationSetID || validLocations[a.locationSetID];
35475 }; // pass a Set of addable preset ids
35478 _this.addablePresetIDs = function (val) {
35479 if (!arguments.length) return _addablePresetIDs; // accept and convert arrays
35481 if (Array.isArray(val)) val = new Set(val);
35482 _addablePresetIDs = val;
35484 if (_addablePresetIDs) {
35485 // reset all presets
35486 _this.collection.forEach(function (p) {
35487 // categories aren't addable
35488 if (p.addable) p.addable(_addablePresetIDs.has(p.id));
35491 _this.collection.forEach(function (p) {
35492 if (p.addable) p.addable(true);
35499 _this.recent = function () {
35500 return presetCollection(utilArrayUniq(_this.getRecents().map(function (d) {
35505 function RibbonItem(preset, source) {
35507 item.preset = preset;
35508 item.source = source;
35510 item.isFavorite = function () {
35511 return item.source === 'favorite';
35514 item.isRecent = function () {
35515 return item.source === 'recent';
35518 item.matches = function (preset) {
35519 return item.preset.id === preset.id;
35522 item.minified = function () {
35524 pID: item.preset.id
35531 function ribbonItemForMinified(d, source) {
35533 var preset = _this.item(d.pID);
35535 if (!preset) return null;
35536 return RibbonItem(preset, source);
35542 _this.getGenericRibbonItems = function () {
35543 return ['point', 'line', 'area'].map(function (id) {
35544 return RibbonItem(_this.item(id), 'generic');
35548 _this.getAddable = function () {
35549 if (!_addablePresetIDs) return [];
35550 return _addablePresetIDs.map(function (id) {
35551 var preset = _this.item(id);
35553 if (preset) return RibbonItem(preset, 'addable');
35555 }).filter(Boolean);
35558 function setRecents(items) {
35560 var minifiedItems = items.map(function (d) {
35561 return d.minified();
35563 corePreferences('preset_recents', JSON.stringify(minifiedItems));
35564 dispatch.call('recentsChange');
35567 _this.getRecents = function () {
35569 // fetch from local storage
35570 _recents = (JSON.parse(corePreferences('preset_recents')) || []).reduce(function (acc, d) {
35571 var item = ribbonItemForMinified(d, 'recent');
35572 if (item && item.preset.addable()) acc.push(item);
35580 _this.addRecent = function (preset, besidePreset, after) {
35581 var recents = _this.getRecents();
35583 var beforeItem = _this.recentMatching(besidePreset);
35585 var toIndex = recents.indexOf(beforeItem);
35586 if (after) toIndex += 1;
35587 var newItem = RibbonItem(preset, 'recent');
35588 recents.splice(toIndex, 0, newItem);
35589 setRecents(recents);
35592 _this.removeRecent = function (preset) {
35593 var item = _this.recentMatching(preset);
35596 var items = _this.getRecents();
35598 items.splice(items.indexOf(item), 1);
35603 _this.recentMatching = function (preset) {
35604 var items = _this.getRecents();
35606 for (var i in items) {
35607 if (items[i].matches(preset)) {
35615 _this.moveItem = function (items, fromIndex, toIndex) {
35616 if (fromIndex === toIndex || fromIndex < 0 || toIndex < 0 || fromIndex >= items.length || toIndex >= items.length) return null;
35617 items.splice(toIndex, 0, items.splice(fromIndex, 1)[0]);
35621 _this.moveRecent = function (item, beforeItem) {
35622 var recents = _this.getRecents();
35624 var fromIndex = recents.indexOf(item);
35625 var toIndex = recents.indexOf(beforeItem);
35627 var items = _this.moveItem(recents, fromIndex, toIndex);
35629 if (items) setRecents(items);
35632 _this.setMostRecent = function (preset) {
35633 if (preset.searchable === false) return;
35635 var items = _this.getRecents();
35637 var item = _this.recentMatching(preset);
35640 items.splice(items.indexOf(item), 1);
35642 item = RibbonItem(preset, 'recent');
35643 } // remove the last recent (first in, first out)
35646 while (items.length >= MAXRECENTS) {
35651 items.unshift(item);
35655 function setFavorites(items) {
35656 _favorites = items;
35657 var minifiedItems = items.map(function (d) {
35658 return d.minified();
35660 corePreferences('preset_favorites', JSON.stringify(minifiedItems)); // call update
35662 dispatch.call('favoritePreset');
35665 _this.addFavorite = function (preset, besidePreset, after) {
35666 var favorites = _this.getFavorites();
35668 var beforeItem = _this.favoriteMatching(besidePreset);
35670 var toIndex = favorites.indexOf(beforeItem);
35671 if (after) toIndex += 1;
35672 var newItem = RibbonItem(preset, 'favorite');
35673 favorites.splice(toIndex, 0, newItem);
35674 setFavorites(favorites);
35677 _this.toggleFavorite = function (preset) {
35678 var favs = _this.getFavorites();
35680 var favorite = _this.favoriteMatching(preset);
35683 favs.splice(favs.indexOf(favorite), 1);
35685 // only allow 10 favorites
35686 if (favs.length === 10) {
35687 // remove the last favorite (last in, first out)
35692 favs.push(RibbonItem(preset, 'favorite'));
35695 setFavorites(favs);
35698 _this.removeFavorite = function (preset) {
35699 var item = _this.favoriteMatching(preset);
35702 var items = _this.getFavorites();
35704 items.splice(items.indexOf(item), 1);
35705 setFavorites(items);
35709 _this.getFavorites = function () {
35711 // fetch from local storage
35712 var rawFavorites = JSON.parse(corePreferences('preset_favorites'));
35714 if (!rawFavorites) {
35716 corePreferences('preset_favorites', JSON.stringify(rawFavorites));
35719 _favorites = rawFavorites.reduce(function (output, d) {
35720 var item = ribbonItemForMinified(d, 'favorite');
35721 if (item && item.preset.addable()) output.push(item);
35729 _this.favoriteMatching = function (preset) {
35730 var favs = _this.getFavorites();
35732 for (var index in favs) {
35733 if (favs[index].matches(preset)) {
35734 return favs[index];
35741 return utilRebind(_this, dispatch, 'on');
35744 function utilTagText(entity) {
35745 var obj = entity && entity.tags || {};
35746 return Object.keys(obj).map(function (k) {
35747 return k + '=' + obj[k];
35750 function utilTotalExtent(array, graph) {
35751 var extent = geoExtent();
35754 for (var i = 0; i < array.length; i++) {
35756 entity = typeof val === 'string' ? graph.hasEntity(val) : val;
35759 extent._extend(entity.extent(graph));
35765 function utilTagDiff(oldTags, newTags) {
35767 var keys = utilArrayUnion(Object.keys(oldTags), Object.keys(newTags)).sort();
35768 keys.forEach(function (k) {
35769 var oldVal = oldTags[k];
35770 var newVal = newTags[k];
35772 if ((oldVal || oldVal === '') && (newVal === undefined || newVal !== oldVal)) {
35778 display: '- ' + k + '=' + oldVal
35782 if ((newVal || newVal === '') && (oldVal === undefined || newVal !== oldVal)) {
35788 display: '+ ' + k + '=' + newVal
35794 function utilEntitySelector(ids) {
35795 return ids.length ? '.' + ids.join(',.') : 'nothing';
35796 } // returns an selector to select entity ids for:
35797 // - entityIDs passed in
35798 // - shallow descendant entityIDs for any of those entities that are relations
35800 function utilEntityOrMemberSelector(ids, graph) {
35801 var seen = new Set(ids);
35802 ids.forEach(collectShallowDescendants);
35803 return utilEntitySelector(Array.from(seen));
35805 function collectShallowDescendants(id) {
35806 var entity = graph.hasEntity(id);
35807 if (!entity || entity.type !== 'relation') return;
35808 entity.members.map(function (member) {
35810 }).forEach(function (id) {
35814 } // returns an selector to select entity ids for:
35815 // - entityIDs passed in
35816 // - deep descendant entityIDs for any of those entities that are relations
35818 function utilEntityOrDeepMemberSelector(ids, graph) {
35819 return utilEntitySelector(utilEntityAndDeepMemberIDs(ids, graph));
35820 } // returns an selector to select entity ids for:
35821 // - entityIDs passed in
35822 // - deep descendant entityIDs for any of those entities that are relations
35824 function utilEntityAndDeepMemberIDs(ids, graph) {
35825 var seen = new Set();
35826 ids.forEach(collectDeepDescendants);
35827 return Array.from(seen);
35829 function collectDeepDescendants(id) {
35830 if (seen.has(id)) return;
35832 var entity = graph.hasEntity(id);
35833 if (!entity || entity.type !== 'relation') return;
35834 entity.members.map(function (member) {
35836 }).forEach(collectDeepDescendants); // recurse
35838 } // returns an selector to select entity ids for:
35839 // - deep descendant entityIDs for any of those entities that are relations
35841 function utilDeepMemberSelector(ids, graph, skipMultipolgonMembers) {
35842 var idsSet = new Set(ids);
35843 var seen = new Set();
35844 var returners = new Set();
35845 ids.forEach(collectDeepDescendants);
35846 return utilEntitySelector(Array.from(returners));
35848 function collectDeepDescendants(id) {
35849 if (seen.has(id)) return;
35852 if (!idsSet.has(id)) {
35856 var entity = graph.hasEntity(id);
35857 if (!entity || entity.type !== 'relation') return;
35858 if (skipMultipolgonMembers && entity.isMultipolygon()) return;
35859 entity.members.map(function (member) {
35861 }).forEach(collectDeepDescendants); // recurse
35863 } // Adds or removes highlight styling for the specified entities
35865 function utilHighlightEntities(ids, highlighted, context) {
35866 context.surface().selectAll(utilEntityOrDeepMemberSelector(ids, context.graph())).classed('highlighted', highlighted);
35867 } // returns an Array that is the union of:
35868 // - nodes for any nodeIDs passed in
35869 // - child nodes of any wayIDs passed in
35870 // - descendant member and child nodes of relationIDs passed in
35872 function utilGetAllNodes(ids, graph) {
35873 var seen = new Set();
35874 var nodes = new Set();
35875 ids.forEach(collectNodes);
35876 return Array.from(nodes);
35878 function collectNodes(id) {
35879 if (seen.has(id)) return;
35881 var entity = graph.hasEntity(id);
35882 if (!entity) return;
35884 if (entity.type === 'node') {
35886 } else if (entity.type === 'way') {
35887 entity.nodes.forEach(collectNodes);
35889 entity.members.map(function (member) {
35891 }).forEach(collectNodes); // recurse
35895 function utilDisplayName(entity) {
35896 var localizedNameKey = 'name:' + _mainLocalizer.languageCode().toLowerCase();
35897 var name = entity.tags[localizedNameKey] || entity.tags.name || '';
35898 if (name) return name;
35900 direction: entity.tags.direction,
35901 from: entity.tags.from,
35902 network: entity.tags.cycle_network || entity.tags.network,
35903 ref: entity.tags.ref,
35904 to: entity.tags.to,
35905 via: entity.tags.via
35907 var keyComponents = [];
35909 if (tags.network) {
35910 keyComponents.push('network');
35914 keyComponents.push('ref');
35915 } // Routes may need more disambiguation based on direction or destination
35918 if (entity.tags.route) {
35919 if (tags.direction) {
35920 keyComponents.push('direction');
35921 } else if (tags.from && tags.to) {
35922 keyComponents.push('from');
35923 keyComponents.push('to');
35926 keyComponents.push('via');
35931 if (keyComponents.length) {
35932 name = _t('inspector.display_name.' + keyComponents.join('_'), tags);
35937 function utilDisplayNameForPath(entity) {
35938 var name = utilDisplayName(entity);
35939 var isFirefox = utilDetect().browser.toLowerCase().indexOf('firefox') > -1;
35940 var isNewChromium = Number(utilDetect().version.split('.')[0]) >= 96.0;
35942 if (!isFirefox && !isNewChromium && name && rtlRegex.test(name)) {
35943 name = fixRTLTextForSvg(name);
35948 function utilDisplayType(id) {
35950 n: _t('inspector.node'),
35951 w: _t('inspector.way'),
35952 r: _t('inspector.relation')
35954 } // `utilDisplayLabel`
35955 // Returns a string suitable for display
35956 // By default returns something like name/ref, fallback to preset type, fallback to OSM type
35957 // "Main Street" or "Tertiary Road"
35958 // If `verbose=true`, include both preset name and feature name.
35959 // "Tertiary Road Main Street"
35962 function utilDisplayLabel(entity, graphOrGeometry, verbose) {
35964 var displayName = utilDisplayName(entity);
35965 var preset = typeof graphOrGeometry === 'string' ? _mainPresetIndex.matchTags(entity.tags, graphOrGeometry) : _mainPresetIndex.match(entity, graphOrGeometry);
35966 var presetName = preset && (preset.suggestion ? preset.subtitle() : preset.name());
35969 result = [presetName, displayName].filter(Boolean).join(' ');
35971 result = displayName || presetName;
35972 } // Fallback to the OSM type (node/way/relation)
35975 return result || utilDisplayType(entity.id);
35977 function utilEntityRoot(entityType) {
35983 } // Returns a single object containing the tags of all the given entities.
35986 // highway: 'service',
35987 // service: 'parking_aisle'
35991 // highway: 'service',
35992 // service: 'driveway',
35997 // highway: 'service',
35998 // service: [ 'driveway', 'parking_aisle' ],
35999 // width: [ '3', undefined ]
36002 function utilCombinedTags(entityIDs, graph) {
36004 var tagCounts = {};
36005 var allKeys = new Set();
36006 var entities = entityIDs.map(function (entityID) {
36007 return graph.hasEntity(entityID);
36008 }).filter(Boolean); // gather the aggregate keys
36010 entities.forEach(function (entity) {
36011 var keys = Object.keys(entity.tags).filter(Boolean);
36012 keys.forEach(function (key) {
36016 entities.forEach(function (entity) {
36017 allKeys.forEach(function (key) {
36018 var value = entity.tags[key]; // purposely allow `undefined`
36020 if (!tags.hasOwnProperty(key)) {
36021 // first value, set as raw
36024 if (!Array.isArray(tags[key])) {
36025 if (tags[key] !== value) {
36026 // first alternate value, replace single value with array
36027 tags[key] = [tags[key], value];
36031 if (tags[key].indexOf(value) === -1) {
36032 // subsequent alternate value, add to array
36033 tags[key].push(value);
36038 var tagHash = key + '=' + value;
36039 if (!tagCounts[tagHash]) tagCounts[tagHash] = 0;
36040 tagCounts[tagHash] += 1;
36044 for (var key in tags) {
36045 if (!Array.isArray(tags[key])) continue; // sort values by frequency then alphabetically
36047 tags[key] = tags[key].sort(function (val1, val2) {
36048 var key = key; // capture
36050 var count2 = tagCounts[key + '=' + val2];
36051 var count1 = tagCounts[key + '=' + val1];
36053 if (count2 !== count1) {
36054 return count2 - count1;
36057 if (val2 && val1) {
36058 return val1.localeCompare(val2);
36061 return val1 ? 1 : -1;
36067 function utilStringQs(str) {
36068 var i = 0; // advance past any leading '?' or '#' characters
36070 while (i < str.length && (str[i] === '?' || str[i] === '#')) {
36074 str = str.slice(i);
36075 return str.split('&').reduce(function (obj, pair) {
36076 var parts = pair.split('=');
36078 if (parts.length === 2) {
36079 obj[parts[0]] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
36085 function utilQsString(obj, noencode) {
36086 // encode everything except special characters used in certain hash parameters:
36087 // "/" in map states, ":", ",", {" and "}" in background
36088 function softEncode(s) {
36089 return encodeURIComponent(s).replace(/(%2F|%3A|%2C|%7B|%7D)/g, decodeURIComponent);
36092 return Object.keys(obj).sort().map(function (key) {
36093 return encodeURIComponent(key) + '=' + (noencode ? softEncode(obj[key]) : encodeURIComponent(obj[key]));
36096 function utilPrefixDOMProperty(property) {
36097 var prefixes = ['webkit', 'ms', 'moz', 'o'];
36099 var n = prefixes.length;
36100 var s = document.body;
36101 if (property in s) return property;
36102 property = property.substr(0, 1).toUpperCase() + property.substr(1);
36105 if (prefixes[i] + property in s) {
36106 return prefixes[i] + property;
36112 function utilPrefixCSSProperty(property) {
36113 var prefixes = ['webkit', 'ms', 'Moz', 'O'];
36115 var n = prefixes.length;
36116 var s = document.body.style;
36118 if (property.toLowerCase() in s) {
36119 return property.toLowerCase();
36123 if (prefixes[i] + property in s) {
36124 return '-' + prefixes[i].toLowerCase() + property.replace(/([A-Z])/g, '-$1').toLowerCase();
36130 var transformProperty;
36131 function utilSetTransform(el, x, y, scale) {
36132 var prop = transformProperty = transformProperty || utilPrefixCSSProperty('Transform');
36133 var translate = utilDetect().opera ? 'translate(' + x + 'px,' + y + 'px)' : 'translate3d(' + x + 'px,' + y + 'px,0)';
36134 return el.style(prop, translate + (scale ? ' scale(' + scale + ')' : ''));
36135 } // Calculates Levenshtein distance between two strings
36136 // see: https://en.wikipedia.org/wiki/Levenshtein_distance
36137 // first converts the strings to lowercase and replaces diacritic marks with ascii equivalents.
36139 function utilEditDistance(a, b) {
36140 a = remove$6(a.toLowerCase());
36141 b = remove$6(b.toLowerCase());
36142 if (a.length === 0) return b.length;
36143 if (b.length === 0) return a.length;
36147 for (i = 0; i <= b.length; i++) {
36151 for (j = 0; j <= a.length; j++) {
36155 for (i = 1; i <= b.length; i++) {
36156 for (j = 1; j <= a.length; j++) {
36157 if (b.charAt(i - 1) === a.charAt(j - 1)) {
36158 matrix[i][j] = matrix[i - 1][j - 1];
36160 matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, // substitution
36161 Math.min(matrix[i][j - 1] + 1, // insertion
36162 matrix[i - 1][j] + 1)); // deletion
36167 return matrix[b.length][a.length];
36168 } // a d3.mouse-alike which
36169 // 1. Only works on HTML elements, not SVG
36170 // 2. Does not cause style recalculation
36172 function utilFastMouse(container) {
36173 var rect = container.getBoundingClientRect();
36174 var rectLeft = rect.left;
36175 var rectTop = rect.top;
36176 var clientLeft = +container.clientLeft;
36177 var clientTop = +container.clientTop;
36178 return function (e) {
36179 return [e.clientX - rectLeft - clientLeft, e.clientY - rectTop - clientTop];
36182 function utilAsyncMap(inputs, func, callback) {
36183 var remaining = inputs.length;
36186 inputs.forEach(function (d, i) {
36187 func(d, function done(err, data) {
36191 if (!remaining) callback(errors, results);
36194 } // wraps an index to an interval [0..length-1]
36196 function utilWrap(index, length) {
36198 index += Math.ceil(-index / length) * length;
36201 return index % length;
36204 * a replacement for functor
36206 * @param {*} value any value
36207 * @returns {Function} a function that returns that value or the value if it's a function
36210 function utilFunctor(value) {
36211 if (typeof value === 'function') return value;
36212 return function () {
36216 function utilNoAuto(selection) {
36217 var isText = selection.size() && selection.node().tagName.toLowerCase() === 'textarea';
36218 return selection // assign 'new-password' even for non-password fields to prevent browsers (Chrome) ignoring 'off'
36219 .attr('autocomplete', 'new-password').attr('autocorrect', 'off').attr('autocapitalize', 'off').attr('spellcheck', isText ? 'true' : 'false');
36220 } // https://stackoverflow.com/questions/194846/is-there-any-kind-of-hash-code-function-in-javascript
36221 // https://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/
36223 function utilHashcode(str) {
36226 if (str.length === 0) {
36230 for (var i = 0; i < str.length; i++) {
36231 var _char = str.charCodeAt(i);
36233 hash = (hash << 5) - hash + _char;
36234 hash = hash & hash; // Convert to 32bit integer
36238 } // Returns version of `str` with all runs of special characters replaced by `_`;
36239 // suitable for HTML ids, classes, selectors, etc.
36241 function utilSafeClassName(str) {
36242 return str.toLowerCase().replace(/[^a-z0-9]+/g, '_');
36243 } // Returns string based on `val` that is highly unlikely to collide with an id
36244 // used previously or that's present elsewhere in the document. Useful for preventing
36245 // browser-provided autofills or when embedding iD on pages with unknown elements.
36247 function utilUniqueDomId(val) {
36248 return 'ideditor-' + utilSafeClassName(val.toString()) + '-' + new Date().getTime().toString();
36249 } // Returns the length of `str` in unicode characters. This can be less than
36250 // `String.length()` since a single unicode character can be composed of multiple
36251 // JavaScript UTF-16 code units.
36253 function utilUnicodeCharsCount(str) {
36254 // Native ES2015 implementations of `Array.from` split strings into unicode characters
36255 return Array.from(str).length;
36256 } // Returns a new string representing `str` cut from its start to `limit` length
36257 // in unicode characters. Note that this runs the risk of splitting graphemes.
36259 function utilUnicodeCharsTruncated(str, limit) {
36260 return Array.from(str).slice(0, limit).join('');
36263 function osmEntity(attrs) {
36264 // For prototypal inheritance.
36265 if (this instanceof osmEntity) return; // Create the appropriate subtype.
36267 if (attrs && attrs.type) {
36268 return osmEntity[attrs.type].apply(this, arguments);
36269 } else if (attrs && attrs.id) {
36270 return osmEntity[osmEntity.id.type(attrs.id)].apply(this, arguments);
36271 } // Initialize a generic Entity (used only in tests).
36274 return new osmEntity().initialize(arguments);
36277 osmEntity.id = function (type) {
36278 return osmEntity.id.fromOSM(type, osmEntity.id.next[type]--);
36281 osmEntity.id.next = {
36288 osmEntity.id.fromOSM = function (type, id) {
36289 return type[0] + id;
36292 osmEntity.id.toOSM = function (id) {
36293 return id.slice(1);
36296 osmEntity.id.type = function (id) {
36303 }; // A function suitable for use as the second argument to d3.selection#data().
36306 osmEntity.key = function (entity) {
36307 return entity.id + 'v' + (entity.v || 0);
36310 var _deprecatedTagValuesByKey;
36312 osmEntity.deprecatedTagValuesByKey = function (dataDeprecated) {
36313 if (!_deprecatedTagValuesByKey) {
36314 _deprecatedTagValuesByKey = {};
36315 dataDeprecated.forEach(function (d) {
36316 var oldKeys = Object.keys(d.old);
36318 if (oldKeys.length === 1) {
36319 var oldKey = oldKeys[0];
36320 var oldValue = d.old[oldKey];
36322 if (oldValue !== '*') {
36323 if (!_deprecatedTagValuesByKey[oldKey]) {
36324 _deprecatedTagValuesByKey[oldKey] = [oldValue];
36326 _deprecatedTagValuesByKey[oldKey].push(oldValue);
36333 return _deprecatedTagValuesByKey;
36336 osmEntity.prototype = {
36338 initialize: function initialize(sources) {
36339 for (var i = 0; i < sources.length; ++i) {
36340 var source = sources[i];
36342 for (var prop in source) {
36343 if (Object.prototype.hasOwnProperty.call(source, prop)) {
36344 if (source[prop] === undefined) {
36347 this[prop] = source[prop];
36353 if (!this.id && this.type) {
36354 this.id = osmEntity.id(this.type);
36357 if (!this.hasOwnProperty('visible')) {
36358 this.visible = true;
36362 Object.freeze(this);
36363 Object.freeze(this.tags);
36364 if (this.loc) Object.freeze(this.loc);
36365 if (this.nodes) Object.freeze(this.nodes);
36366 if (this.members) Object.freeze(this.members);
36371 copy: function copy(resolver, copies) {
36372 if (copies[this.id]) return copies[this.id];
36373 var copy = osmEntity(this, {
36378 copies[this.id] = copy;
36381 osmId: function osmId() {
36382 return osmEntity.id.toOSM(this.id);
36384 isNew: function isNew() {
36385 return this.osmId() < 0;
36387 update: function update(attrs) {
36388 return osmEntity(this, attrs, {
36389 v: 1 + (this.v || 0)
36392 mergeTags: function mergeTags(tags) {
36393 var merged = Object.assign({}, this.tags); // shallow copy
36395 var changed = false;
36397 for (var k in tags) {
36398 var t1 = merged[k];
36404 } else if (t1 !== t2) {
36406 merged[k] = utilUnicodeCharsTruncated(utilArrayUnion(t1.split(/;\s*/), t2.split(/;\s*/)).join(';'), 255 // avoid exceeding character limit; see also services/osm.js -> maxCharsForTagValue()
36411 return changed ? this.update({
36415 intersects: function intersects(extent, resolver) {
36416 return this.extent(resolver).intersects(extent);
36418 hasNonGeometryTags: function hasNonGeometryTags() {
36419 return Object.keys(this.tags).some(function (k) {
36420 return k !== 'area';
36423 hasParentRelations: function hasParentRelations(resolver) {
36424 return resolver.parentRelations(this).length > 0;
36426 hasInterestingTags: function hasInterestingTags() {
36427 return Object.keys(this.tags).some(osmIsInterestingTag);
36429 isHighwayIntersection: function isHighwayIntersection() {
36432 isDegenerate: function isDegenerate() {
36435 deprecatedTags: function deprecatedTags(dataDeprecated) {
36436 var tags = this.tags; // if there are no tags, none can be deprecated
36438 if (Object.keys(tags).length === 0) return [];
36439 var deprecated = [];
36440 dataDeprecated.forEach(function (d) {
36441 var oldKeys = Object.keys(d.old);
36444 var hasExistingValues = Object.keys(d.replace).some(function (replaceKey) {
36445 if (!tags[replaceKey] || d.old[replaceKey]) return false;
36446 var replaceValue = d.replace[replaceKey];
36447 if (replaceValue === '*') return false;
36448 if (replaceValue === tags[replaceKey]) return false;
36450 }); // don't flag deprecated tags if the upgrade path would overwrite existing data - #7843
36452 if (hasExistingValues) return;
36455 var matchesDeprecatedTags = oldKeys.every(function (oldKey) {
36456 if (!tags[oldKey]) return false;
36457 if (d.old[oldKey] === '*') return true;
36458 if (d.old[oldKey] === tags[oldKey]) return true;
36459 var vals = tags[oldKey].split(';').filter(Boolean);
36461 if (vals.length === 0) {
36463 } else if (vals.length > 1) {
36464 return vals.indexOf(d.old[oldKey]) !== -1;
36466 if (tags[oldKey] === d.old[oldKey]) {
36467 if (d.replace && d.old[oldKey] === d.replace[oldKey]) {
36468 var replaceKeys = Object.keys(d.replace);
36469 return !replaceKeys.every(function (replaceKey) {
36470 return tags[replaceKey] === d.replace[replaceKey];
36481 if (matchesDeprecatedTags) {
36482 deprecated.push(d);
36489 function osmLanes(entity) {
36490 if (entity.type !== 'way') return null;
36491 if (!entity.tags.highway) return null;
36492 var tags = entity.tags;
36493 var isOneWay = entity.isOneWay();
36494 var laneCount = getLaneCount(tags, isOneWay);
36495 var maxspeed = parseMaxspeed(tags);
36496 var laneDirections = parseLaneDirections(tags, isOneWay, laneCount);
36497 var forward = laneDirections.forward;
36498 var backward = laneDirections.backward;
36499 var bothways = laneDirections.bothways; // parse the piped string 'x|y|z' format
36501 var turnLanes = {};
36502 turnLanes.unspecified = parseTurnLanes(tags['turn:lanes']);
36503 turnLanes.forward = parseTurnLanes(tags['turn:lanes:forward']);
36504 turnLanes.backward = parseTurnLanes(tags['turn:lanes:backward']);
36505 var maxspeedLanes = {};
36506 maxspeedLanes.unspecified = parseMaxspeedLanes(tags['maxspeed:lanes'], maxspeed);
36507 maxspeedLanes.forward = parseMaxspeedLanes(tags['maxspeed:lanes:forward'], maxspeed);
36508 maxspeedLanes.backward = parseMaxspeedLanes(tags['maxspeed:lanes:backward'], maxspeed);
36510 psvLanes.unspecified = parseMiscLanes(tags['psv:lanes']);
36511 psvLanes.forward = parseMiscLanes(tags['psv:lanes:forward']);
36512 psvLanes.backward = parseMiscLanes(tags['psv:lanes:backward']);
36514 busLanes.unspecified = parseMiscLanes(tags['bus:lanes']);
36515 busLanes.forward = parseMiscLanes(tags['bus:lanes:forward']);
36516 busLanes.backward = parseMiscLanes(tags['bus:lanes:backward']);
36517 var taxiLanes = {};
36518 taxiLanes.unspecified = parseMiscLanes(tags['taxi:lanes']);
36519 taxiLanes.forward = parseMiscLanes(tags['taxi:lanes:forward']);
36520 taxiLanes.backward = parseMiscLanes(tags['taxi:lanes:backward']);
36522 hovLanes.unspecified = parseMiscLanes(tags['hov:lanes']);
36523 hovLanes.forward = parseMiscLanes(tags['hov:lanes:forward']);
36524 hovLanes.backward = parseMiscLanes(tags['hov:lanes:backward']);
36526 hgvLanes.unspecified = parseMiscLanes(tags['hgv:lanes']);
36527 hgvLanes.forward = parseMiscLanes(tags['hgv:lanes:forward']);
36528 hgvLanes.backward = parseMiscLanes(tags['hgv:lanes:backward']);
36529 var bicyclewayLanes = {};
36530 bicyclewayLanes.unspecified = parseBicycleWay(tags['bicycleway:lanes']);
36531 bicyclewayLanes.forward = parseBicycleWay(tags['bicycleway:lanes:forward']);
36532 bicyclewayLanes.backward = parseBicycleWay(tags['bicycleway:lanes:backward']);
36537 }; // map forward/backward/unspecified of each lane type to lanesObj
36539 mapToLanesObj(lanesObj, turnLanes, 'turnLane');
36540 mapToLanesObj(lanesObj, maxspeedLanes, 'maxspeed');
36541 mapToLanesObj(lanesObj, psvLanes, 'psv');
36542 mapToLanesObj(lanesObj, busLanes, 'bus');
36543 mapToLanesObj(lanesObj, taxiLanes, 'taxi');
36544 mapToLanesObj(lanesObj, hovLanes, 'hov');
36545 mapToLanesObj(lanesObj, hgvLanes, 'hgv');
36546 mapToLanesObj(lanesObj, bicyclewayLanes, 'bicycleway');
36552 backward: backward,
36553 bothways: bothways,
36554 turnLanes: turnLanes,
36555 maxspeed: maxspeed,
36556 maxspeedLanes: maxspeedLanes,
36557 psvLanes: psvLanes,
36558 busLanes: busLanes,
36559 taxiLanes: taxiLanes,
36560 hovLanes: hovLanes,
36561 hgvLanes: hgvLanes,
36562 bicyclewayLanes: bicyclewayLanes
36568 function getLaneCount(tags, isOneWay) {
36572 count = parseInt(tags.lanes, 10);
36579 switch (tags.highway) {
36582 count = isOneWay ? 2 : 4;
36586 count = isOneWay ? 1 : 2;
36593 function parseMaxspeed(tags) {
36594 var maxspeed = tags.maxspeed;
36595 if (!maxspeed) return;
36596 var maxspeedRegex = /^([0-9][\.0-9]+?)(?:[ ]?(?:km\/h|kmh|kph|mph|knots))?$/;
36597 if (!maxspeedRegex.test(maxspeed)) return;
36598 return parseInt(maxspeed, 10);
36601 function parseLaneDirections(tags, isOneWay, laneCount) {
36602 var forward = parseInt(tags['lanes:forward'], 10);
36603 var backward = parseInt(tags['lanes:backward'], 10);
36604 var bothways = parseInt(tags['lanes:both_ways'], 10) > 0 ? 1 : 0;
36606 if (parseInt(tags.oneway, 10) === -1) {
36609 backward = laneCount;
36610 } else if (isOneWay) {
36611 forward = laneCount;
36614 } else if (isNaN(forward) && isNaN(backward)) {
36615 backward = Math.floor((laneCount - bothways) / 2);
36616 forward = laneCount - bothways - backward;
36617 } else if (isNaN(forward)) {
36618 if (backward > laneCount - bothways) {
36619 backward = laneCount - bothways;
36622 forward = laneCount - bothways - backward;
36623 } else if (isNaN(backward)) {
36624 if (forward > laneCount - bothways) {
36625 forward = laneCount - bothways;
36628 backward = laneCount - bothways - forward;
36633 backward: backward,
36638 function parseTurnLanes(tag) {
36640 var validValues = ['left', 'slight_left', 'sharp_left', 'through', 'right', 'slight_right', 'sharp_right', 'reverse', 'merge_to_left', 'merge_to_right', 'none'];
36641 return tag.split('|').map(function (s) {
36642 if (s === '') s = 'none';
36643 return s.split(';').map(function (d) {
36644 return validValues.indexOf(d) === -1 ? 'unknown' : d;
36649 function parseMaxspeedLanes(tag, maxspeed) {
36651 return tag.split('|').map(function (s) {
36652 if (s === 'none') return s;
36653 var m = parseInt(s, 10);
36654 if (s === '' || m === maxspeed) return null;
36655 return isNaN(m) ? 'unknown' : m;
36659 function parseMiscLanes(tag) {
36661 var validValues = ['yes', 'no', 'designated'];
36662 return tag.split('|').map(function (s) {
36663 if (s === '') s = 'no';
36664 return validValues.indexOf(s) === -1 ? 'unknown' : s;
36668 function parseBicycleWay(tag) {
36670 var validValues = ['yes', 'no', 'designated', 'lane'];
36671 return tag.split('|').map(function (s) {
36672 if (s === '') s = 'no';
36673 return validValues.indexOf(s) === -1 ? 'unknown' : s;
36677 function mapToLanesObj(lanesObj, data, key) {
36678 if (data.forward) {
36679 data.forward.forEach(function (l, i) {
36680 if (!lanesObj.forward[i]) lanesObj.forward[i] = {};
36681 lanesObj.forward[i][key] = l;
36685 if (data.backward) {
36686 data.backward.forEach(function (l, i) {
36687 if (!lanesObj.backward[i]) lanesObj.backward[i] = {};
36688 lanesObj.backward[i][key] = l;
36692 if (data.unspecified) {
36693 data.unspecified.forEach(function (l, i) {
36694 if (!lanesObj.unspecified[i]) lanesObj.unspecified[i] = {};
36695 lanesObj.unspecified[i][key] = l;
36700 function osmWay() {
36701 if (!(this instanceof osmWay)) {
36702 return new osmWay().initialize(arguments);
36703 } else if (arguments.length) {
36704 this.initialize(arguments);
36707 osmEntity.way = osmWay;
36708 osmWay.prototype = Object.create(osmEntity.prototype);
36709 Object.assign(osmWay.prototype, {
36712 copy: function copy(resolver, copies) {
36713 if (copies[this.id]) return copies[this.id];
36714 var copy = osmEntity.prototype.copy.call(this, resolver, copies);
36715 var nodes = this.nodes.map(function (id) {
36716 return resolver.entity(id).copy(resolver, copies).id;
36718 copy = copy.update({
36721 copies[this.id] = copy;
36724 extent: function extent(resolver) {
36725 return resolver["transient"](this, 'extent', function () {
36726 var extent = geoExtent();
36728 for (var i = 0; i < this.nodes.length; i++) {
36729 var node = resolver.hasEntity(this.nodes[i]);
36732 extent._extend(node.extent());
36739 first: function first() {
36740 return this.nodes[0];
36742 last: function last() {
36743 return this.nodes[this.nodes.length - 1];
36745 contains: function contains(node) {
36746 return this.nodes.indexOf(node) >= 0;
36748 affix: function affix(node) {
36749 if (this.nodes[0] === node) return 'prefix';
36750 if (this.nodes[this.nodes.length - 1] === node) return 'suffix';
36752 layer: function layer() {
36753 // explicit layer tag, clamp between -10, 10..
36754 if (isFinite(this.tags.layer)) {
36755 return Math.max(-10, Math.min(+this.tags.layer, 10));
36756 } // implied layer tag..
36759 if (this.tags.covered === 'yes') return -1;
36760 if (this.tags.location === 'overground') return 1;
36761 if (this.tags.location === 'underground') return -1;
36762 if (this.tags.location === 'underwater') return -10;
36763 if (this.tags.power === 'line') return 10;
36764 if (this.tags.power === 'minor_line') return 10;
36765 if (this.tags.aerialway) return 10;
36766 if (this.tags.bridge) return 1;
36767 if (this.tags.cutting) return -1;
36768 if (this.tags.tunnel) return -1;
36769 if (this.tags.waterway) return -1;
36770 if (this.tags.man_made === 'pipeline') return -10;
36771 if (this.tags.boundary) return -10;
36774 // the approximate width of the line based on its tags except its `width` tag
36775 impliedLineWidthMeters: function impliedLineWidthMeters() {
36776 var averageWidths = {
36778 // width is for single lane
36805 // width includes ties and rail bed, not just track gauge
36828 for (var key in averageWidths) {
36829 if (this.tags[key] && averageWidths[key][this.tags[key]]) {
36830 var width = averageWidths[key][this.tags[key]];
36832 if (key === 'highway') {
36833 var laneCount = this.tags.lanes && parseInt(this.tags.lanes, 10);
36834 if (!laneCount) laneCount = this.isOneWay() ? 1 : 2;
36835 return width * laneCount;
36844 isOneWay: function isOneWay() {
36845 // explicit oneway tag..
36850 'reversible': true,
36851 'alternating': true,
36856 if (values[this.tags.oneway] !== undefined) {
36857 return values[this.tags.oneway];
36858 } // implied oneway tag..
36861 for (var key in this.tags) {
36862 if (key in osmOneWayTags && this.tags[key] in osmOneWayTags[key]) {
36869 // Some identifier for tag that implies that this way is "sided",
36870 // i.e. the right side is the 'inside' (e.g. the right side of a
36871 // natural=cliff is lower).
36872 sidednessIdentifier: function sidednessIdentifier() {
36873 for (var key in this.tags) {
36874 var value = this.tags[key];
36876 if (key in osmRightSideIsInsideTags && value in osmRightSideIsInsideTags[key]) {
36877 if (osmRightSideIsInsideTags[key][value] === true) {
36880 // if the map's value is something other than a
36881 // literal true, we should use it so we can
36882 // special case some keys (e.g. natural=coastline
36883 // is handled differently to other naturals).
36884 return osmRightSideIsInsideTags[key][value];
36891 isSided: function isSided() {
36892 if (this.tags.two_sided === 'yes') {
36896 return this.sidednessIdentifier() !== null;
36898 lanes: function lanes() {
36899 return osmLanes(this);
36901 isClosed: function isClosed() {
36902 return this.nodes.length > 1 && this.first() === this.last();
36904 isConvex: function isConvex(resolver) {
36905 if (!this.isClosed() || this.isDegenerate()) return null;
36906 var nodes = utilArrayUniq(resolver.childNodes(this));
36907 var coords = nodes.map(function (n) {
36913 for (var i = 0; i < coords.length; i++) {
36914 var o = coords[(i + 1) % coords.length];
36916 var b = coords[(i + 2) % coords.length];
36917 var res = geoVecCross(a, b, o);
36918 curr = res > 0 ? 1 : res < 0 ? -1 : 0;
36922 } else if (prev && curr !== prev) {
36931 // returns an object with the tag that implies this is an area, if any
36932 tagSuggestingArea: function tagSuggestingArea() {
36933 return osmTagSuggestingArea(this.tags);
36935 isArea: function isArea() {
36936 if (this.tags.area === 'yes') return true;
36937 if (!this.isClosed() || this.tags.area === 'no') return false;
36938 return this.tagSuggestingArea() !== null;
36940 isDegenerate: function isDegenerate() {
36941 return new Set(this.nodes).size < (this.isArea() ? 3 : 2);
36943 areAdjacent: function areAdjacent(n1, n2) {
36944 for (var i = 0; i < this.nodes.length; i++) {
36945 if (this.nodes[i] === n1) {
36946 if (this.nodes[i - 1] === n2) return true;
36947 if (this.nodes[i + 1] === n2) return true;
36953 geometry: function geometry(graph) {
36954 return graph["transient"](this, 'geometry', function () {
36955 return this.isArea() ? 'area' : 'line';
36958 // returns an array of objects representing the segments between the nodes in this way
36959 segments: function segments(graph) {
36960 function segmentExtent(graph) {
36961 var n1 = graph.hasEntity(this.nodes[0]);
36962 var n2 = graph.hasEntity(this.nodes[1]);
36963 return n1 && n2 && geoExtent([[Math.min(n1.loc[0], n2.loc[0]), Math.min(n1.loc[1], n2.loc[1])], [Math.max(n1.loc[0], n2.loc[0]), Math.max(n1.loc[1], n2.loc[1])]]);
36966 return graph["transient"](this, 'segments', function () {
36969 for (var i = 0; i < this.nodes.length - 1; i++) {
36971 id: this.id + '-' + i,
36974 nodes: [this.nodes[i], this.nodes[i + 1]],
36975 extent: segmentExtent
36982 // If this way is not closed, append the beginning node to the end of the nodelist to close it.
36983 close: function close() {
36984 if (this.isClosed() || !this.nodes.length) return this;
36985 var nodes = this.nodes.slice();
36986 nodes = nodes.filter(noRepeatNodes);
36987 nodes.push(nodes[0]);
36988 return this.update({
36992 // If this way is closed, remove any connector nodes from the end of the nodelist to unclose it.
36993 unclose: function unclose() {
36994 if (!this.isClosed()) return this;
36995 var nodes = this.nodes.slice();
36996 var connector = this.first();
36997 var i = nodes.length - 1; // remove trailing connectors..
36999 while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37000 nodes.splice(i, 1);
37001 i = nodes.length - 1;
37004 nodes = nodes.filter(noRepeatNodes);
37005 return this.update({
37009 // Adds a node (id) in front of the node which is currently at position index.
37010 // If index is undefined, the node will be added to the end of the way for linear ways,
37011 // or just before the final connecting node for circular ways.
37012 // Consecutive duplicates are eliminated including existing ones.
37013 // Circularity is always preserved when adding a node.
37014 addNode: function addNode(id, index) {
37015 var nodes = this.nodes.slice();
37016 var isClosed = this.isClosed();
37017 var max = isClosed ? nodes.length - 1 : nodes.length;
37019 if (index === undefined) {
37023 if (index < 0 || index > max) {
37024 throw new RangeError('index ' + index + ' out of range 0..' + max);
37025 } // If this is a closed way, remove all connector nodes except the first one
37026 // (there may be duplicates) and adjust index if necessary..
37030 var connector = this.first(); // leading connectors..
37034 while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
37035 nodes.splice(i, 1);
37036 if (index > i) index--;
37037 } // trailing connectors..
37040 i = nodes.length - 1;
37042 while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37043 nodes.splice(i, 1);
37044 if (index > i) index--;
37045 i = nodes.length - 1;
37049 nodes.splice(index, 0, id);
37050 nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37052 if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37053 nodes.push(nodes[0]);
37056 return this.update({
37060 // Replaces the node which is currently at position index with the given node (id).
37061 // Consecutive duplicates are eliminated including existing ones.
37062 // Circularity is preserved when updating a node.
37063 updateNode: function updateNode(id, index) {
37064 var nodes = this.nodes.slice();
37065 var isClosed = this.isClosed();
37066 var max = nodes.length - 1;
37068 if (index === undefined || index < 0 || index > max) {
37069 throw new RangeError('index ' + index + ' out of range 0..' + max);
37070 } // If this is a closed way, remove all connector nodes except the first one
37071 // (there may be duplicates) and adjust index if necessary..
37075 var connector = this.first(); // leading connectors..
37079 while (i < nodes.length && nodes.length > 2 && nodes[i] === connector) {
37080 nodes.splice(i, 1);
37081 if (index > i) index--;
37082 } // trailing connectors..
37085 i = nodes.length - 1;
37087 while (i > 0 && nodes.length > 1 && nodes[i] === connector) {
37088 nodes.splice(i, 1);
37089 if (index === i) index = 0; // update leading connector instead
37091 i = nodes.length - 1;
37095 nodes.splice(index, 1, id);
37096 nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37098 if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37099 nodes.push(nodes[0]);
37102 return this.update({
37106 // Replaces each occurrence of node id needle with replacement.
37107 // Consecutive duplicates are eliminated including existing ones.
37108 // Circularity is preserved.
37109 replaceNode: function replaceNode(needleID, replacementID) {
37110 var nodes = this.nodes.slice();
37111 var isClosed = this.isClosed();
37113 for (var i = 0; i < nodes.length; i++) {
37114 if (nodes[i] === needleID) {
37115 nodes[i] = replacementID;
37119 nodes = nodes.filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37121 if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37122 nodes.push(nodes[0]);
37125 return this.update({
37129 // Removes each occurrence of node id.
37130 // Consecutive duplicates are eliminated including existing ones.
37131 // Circularity is preserved.
37132 removeNode: function removeNode(id) {
37133 var nodes = this.nodes.slice();
37134 var isClosed = this.isClosed();
37135 nodes = nodes.filter(function (node) {
37136 return node !== id;
37137 }).filter(noRepeatNodes); // If the way was closed before, append a connector node to keep it closed..
37139 if (isClosed && (nodes.length === 1 || nodes[0] !== nodes[nodes.length - 1])) {
37140 nodes.push(nodes[0]);
37143 return this.update({
37147 asJXON: function asJXON(changeset_id) {
37150 '@id': this.osmId(),
37151 '@version': this.version || 0,
37152 nd: this.nodes.map(function (id) {
37155 ref: osmEntity.id.toOSM(id)
37159 tag: Object.keys(this.tags).map(function (k) {
37170 if (changeset_id) {
37171 r.way['@changeset'] = changeset_id;
37176 asGeoJSON: function asGeoJSON(resolver) {
37177 return resolver["transient"](this, 'GeoJSON', function () {
37178 var coordinates = resolver.childNodes(this).map(function (n) {
37182 if (this.isArea() && this.isClosed()) {
37185 coordinates: [coordinates]
37189 type: 'LineString',
37190 coordinates: coordinates
37195 area: function area(resolver) {
37196 return resolver["transient"](this, 'area', function () {
37197 var nodes = resolver.childNodes(this);
37200 coordinates: [nodes.map(function (n) {
37205 if (!this.isClosed() && nodes.length) {
37206 json.coordinates[0].push(nodes[0].loc);
37209 var area = d3_geoArea(json); // Heuristic for detecting counterclockwise winding order. Assumes
37210 // that OpenStreetMap polygons are not hemisphere-spanning.
37212 if (area > 2 * Math.PI) {
37213 json.coordinates[0] = json.coordinates[0].reverse();
37214 area = d3_geoArea(json);
37217 return isNaN(area) ? 0 : area;
37220 }); // Filter function to eliminate consecutive duplicates.
37222 function noRepeatNodes(node, i, arr) {
37223 return i === 0 || node !== arr[i - 1];
37227 // 1. Relation tagged with `type=multipolygon` and no interesting tags.
37228 // 2. One and only one member with the `outer` role. Must be a way with interesting tags.
37229 // 3. No members without a role.
37231 // Old multipolygons are no longer recommended but are still rendered as areas by iD.
37233 function osmOldMultipolygonOuterMemberOfRelation(entity, graph) {
37234 if (entity.type !== 'relation' || !entity.isMultipolygon() || Object.keys(entity.tags).filter(osmIsInterestingTag).length > 1) {
37240 for (var memberIndex in entity.members) {
37241 var member = entity.members[memberIndex];
37243 if (!member.role || member.role === 'outer') {
37244 if (outerMember) return false;
37245 if (member.type !== 'way') return false;
37246 if (!graph.hasEntity(member.id)) return false;
37247 outerMember = graph.entity(member.id);
37249 if (Object.keys(outerMember.tags).filter(osmIsInterestingTag).length === 0) {
37255 return outerMember;
37256 } // For fixing up rendering of multipolygons with tags on the outer member.
37257 // https://github.com/openstreetmap/iD/issues/613
37259 function osmIsOldMultipolygonOuterMember(entity, graph) {
37260 if (entity.type !== 'way' || Object.keys(entity.tags).filter(osmIsInterestingTag).length === 0) {
37264 var parents = graph.parentRelations(entity);
37265 if (parents.length !== 1) return false;
37266 var parent = parents[0];
37268 if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
37272 var members = parent.members,
37275 for (var i = 0; i < members.length; i++) {
37276 member = members[i];
37278 if (member.id === entity.id && member.role && member.role !== 'outer') {
37279 // Not outer member
37283 if (member.id !== entity.id && (!member.role || member.role === 'outer')) {
37284 // Not a simple multipolygon
37291 function osmOldMultipolygonOuterMember(entity, graph) {
37292 if (entity.type !== 'way') return false;
37293 var parents = graph.parentRelations(entity);
37294 if (parents.length !== 1) return false;
37295 var parent = parents[0];
37297 if (!parent.isMultipolygon() || Object.keys(parent.tags).filter(osmIsInterestingTag).length > 1) {
37301 var members = parent.members,
37305 for (var i = 0; i < members.length; i++) {
37306 member = members[i];
37308 if (!member.role || member.role === 'outer') {
37309 if (outerMember) return false; // Not a simple multipolygon
37311 outerMember = member;
37315 if (!outerMember) return false;
37316 var outerEntity = graph.hasEntity(outerMember.id);
37318 if (!outerEntity || !Object.keys(outerEntity.tags).filter(osmIsInterestingTag).length) {
37322 return outerEntity;
37323 } // Join `toJoin` array into sequences of connecting ways.
37324 // Segments which share identical start/end nodes will, as much as possible,
37325 // be connected with each other.
37327 // The return value is a nested array. Each constituent array contains elements
37328 // of `toJoin` which have been determined to connect.
37330 // Each consitituent array also has a `nodes` property whose value is an
37331 // ordered array of member nodes, with appropriate order reversal and
37332 // start/end coordinate de-duplication.
37334 // Members of `toJoin` must have, at minimum, `type` and `id` properties.
37335 // Thus either an array of `osmWay`s or a relation member array may be used.
37337 // If an member is an `osmWay`, its tags and childnodes may be reversed via
37338 // `actionReverse` in the output.
37340 // The returned sequences array also has an `actions` array property, containing
37341 // any reversal actions that should be applied to the graph, should the calling
37342 // code attempt to actually join the given ways.
37344 // Incomplete members (those for which `graph.hasEntity(element.id)` returns
37345 // false) and non-way members are ignored.
37348 function osmJoinWays(toJoin, graph) {
37349 function resolve(member) {
37350 return graph.childNodes(graph.entity(member.id));
37353 function reverse(item) {
37354 var action = actionReverse(item.id, {
37355 reverseOneway: true
37357 sequences.actions.push(action);
37358 return item instanceof osmWay ? action(graph).entity(item.id) : item;
37359 } // make a copy containing only the items to join
37362 toJoin = toJoin.filter(function (member) {
37363 return member.type === 'way' && graph.hasEntity(member.id);
37364 }); // Are the things we are joining relation members or `osmWays`?
37365 // If `osmWays`, skip the "prefer a forward path" code below (see #4872)
37368 var joinAsMembers = true;
37370 for (i = 0; i < toJoin.length; i++) {
37371 if (toJoin[i] instanceof osmWay) {
37372 joinAsMembers = false;
37377 var sequences = [];
37378 sequences.actions = [];
37380 while (toJoin.length) {
37381 // start a new sequence
37382 var item = toJoin.shift();
37383 var currWays = [item];
37384 var currNodes = resolve(item).slice(); // add to it
37386 while (toJoin.length) {
37387 var start = currNodes[0];
37388 var end = currNodes[currNodes.length - 1];
37390 var nodes = null; // Find the next way/member to join.
37392 for (i = 0; i < toJoin.length; i++) {
37394 nodes = resolve(item); // (for member ordering only, not way ordering - see #4872)
37395 // Strongly prefer to generate a forward path that preserves the order
37396 // of the members array. For multipolygons and most relations, member
37397 // order does not matter - but for routes, it does. (see #4589)
37398 // If we started this sequence backwards (i.e. next member way attaches to
37399 // the start node and not the end node), reverse the initial way before continuing.
37401 if (joinAsMembers && currWays.length === 1 && nodes[0] !== end && nodes[nodes.length - 1] !== end && (nodes[nodes.length - 1] === start || nodes[0] === start)) {
37402 currWays[0] = reverse(currWays[0]);
37403 currNodes.reverse();
37404 start = currNodes[0];
37405 end = currNodes[currNodes.length - 1];
37408 if (nodes[0] === end) {
37409 fn = currNodes.push; // join to end
37411 nodes = nodes.slice(1);
37413 } else if (nodes[nodes.length - 1] === end) {
37414 fn = currNodes.push; // join to end
37416 nodes = nodes.slice(0, -1).reverse();
37417 item = reverse(item);
37419 } else if (nodes[nodes.length - 1] === start) {
37420 fn = currNodes.unshift; // join to beginning
37422 nodes = nodes.slice(0, -1);
37424 } else if (nodes[0] === start) {
37425 fn = currNodes.unshift; // join to beginning
37427 nodes = nodes.slice(1).reverse();
37428 item = reverse(item);
37436 // couldn't find a joinable way/member
37440 fn.apply(currWays, [item]);
37441 fn.apply(currNodes, nodes);
37442 toJoin.splice(i, 1);
37445 currWays.nodes = currNodes;
37446 sequences.push(currWays);
37452 function actionAddMember(relationId, member, memberIndex, insertPair) {
37453 return function action(graph) {
37454 var relation = graph.entity(relationId); // There are some special rules for Public Transport v2 routes.
37456 var isPTv2 = /stop|platform/.test(member.role);
37458 if ((isNaN(memberIndex) || insertPair) && member.type === 'way' && !isPTv2) {
37459 // Try to perform sensible inserts based on how the ways join together
37460 graph = addWayMember(relation, graph);
37462 // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
37463 // Stops and Platforms for PTv2 should be ordered first.
37464 // hack: We do not currently have the ability to place them in the exactly correct order.
37465 if (isPTv2 && isNaN(memberIndex)) {
37469 graph = graph.replace(relation.addMember(member, memberIndex));
37473 }; // Add a way member into the relation "wherever it makes sense".
37474 // In this situation we were not supplied a memberIndex.
37476 function addWayMember(relation, graph) {
37477 var groups, tempWay, item, i, j, k; // remove PTv2 stops and platforms before doing anything.
37479 var PTv2members = [];
37482 for (i = 0; i < relation.members.length; i++) {
37483 var m = relation.members[i];
37485 if (/stop|platform/.test(m.role)) {
37486 PTv2members.push(m);
37492 relation = relation.update({
37497 // We're adding a member that must stay paired with an existing member.
37498 // (This feature is used by `actionSplit`)
37500 // This is tricky because the members may exist multiple times in the
37501 // member list, and with different A-B/B-A ordering and different roles.
37502 // (e.g. a bus route that loops out and back - #4589).
37504 // Replace the existing member with a temporary way,
37505 // so that `osmJoinWays` can treat the pair like a single way.
37508 nodes: insertPair.nodes
37510 graph = graph.replace(tempWay);
37516 var tempRelation = relation.replaceMember({
37517 id: insertPair.originalID
37518 }, tempMember, true);
37519 groups = utilArrayGroupBy(tempRelation.members, 'type');
37520 groups.way = groups.way || [];
37522 // Add the member anywhere, one time. Just push and let `osmJoinWays` decide where to put it.
37523 groups = utilArrayGroupBy(relation.members, 'type');
37524 groups.way = groups.way || [];
37525 groups.way.push(member);
37528 members = withIndex(groups.way);
37529 var joined = osmJoinWays(members, graph); // `joined` might not contain all of the way members,
37530 // But will contain only the completed (downloaded) members
37532 for (i = 0; i < joined.length; i++) {
37533 var segment = joined[i];
37534 var nodes = segment.nodes.slice();
37535 var startIndex = segment[0].index; // j = array index in `members` where this segment starts
37537 for (j = 0; j < members.length; j++) {
37538 if (members[j].index === startIndex) {
37541 } // k = each member in segment
37544 for (k = 0; k < segment.length; k++) {
37546 var way = graph.entity(item.id); // If this is a paired item, generate members in correct order and role
37548 if (tempWay && item.id === tempWay.id) {
37549 if (nodes[0].id === insertPair.nodes[0]) {
37551 id: insertPair.originalID,
37555 id: insertPair.insertedID,
37561 id: insertPair.insertedID,
37565 id: insertPair.originalID,
37570 } // reorder `members` if necessary
37574 if (j + k >= members.length || item.index !== members[j + k].index) {
37575 moveMember(members, item.index, j + k);
37579 nodes.splice(0, way.nodes.length - 1);
37584 graph = graph.remove(tempWay);
37585 } // Final pass: skip dead items, split pairs, remove index properties
37588 var wayMembers = [];
37590 for (i = 0; i < members.length; i++) {
37592 if (item.index === -1) continue;
37595 wayMembers.push(item.pair[0]);
37596 wayMembers.push(item.pair[1]);
37598 wayMembers.push(utilObjectOmit(item, ['index']));
37600 } // Put stops and platforms first, then nodes, ways, relations
37601 // This is recommended for Public Transport v2 routes:
37602 // see https://wiki.openstreetmap.org/wiki/Public_transport#Service_routes
37605 var newMembers = PTv2members.concat(groups.node || [], wayMembers, groups.relation || []);
37606 return graph.replace(relation.update({
37607 members: newMembers
37608 })); // `moveMember()` changes the `members` array in place by splicing
37609 // the item with `.index = findIndex` to where it belongs,
37610 // and marking the old position as "dead" with `.index = -1`
37614 // members 0 1 2 3 4 5 6 7 8 9 keep 5 in j+k
37618 // members 0 1 2 3 4 5 6 7 8 9 move 4 to j+k
37619 // members 0 1 2 3 x 5 4 6 7 8 9 moved
37623 // members 0 1 2 3 x 5 4 6 7 8 9 move 7 to j+k
37624 // members 0 1 2 3 x 5 4 7 6 x 8 9 moved
37628 // members 0 1 2 3 x 5 4 7 6 x 8 9 keep 6 in j+k
37631 function moveMember(arr, findIndex, toIndex) {
37634 for (i = 0; i < arr.length; i++) {
37635 if (arr[i].index === findIndex) {
37640 var item = Object.assign({}, arr[i]); // shallow copy
37642 arr[i].index = -1; // mark as dead
37644 item.index = toIndex;
37645 arr.splice(toIndex, 0, item);
37646 } // This is the same as `Relation.indexedMembers`,
37647 // Except we don't want to index all the members, only the ways
37650 function withIndex(arr) {
37651 var result = new Array(arr.length);
37653 for (var i = 0; i < arr.length; i++) {
37654 result[i] = Object.assign({}, arr[i]); // shallow copy
37656 result[i].index = i;
37664 function actionAddMidpoint(midpoint, node) {
37665 return function (graph) {
37666 graph = graph.replace(node.move(midpoint.loc));
37667 var parents = utilArrayIntersection(graph.parentWays(graph.entity(midpoint.edge[0])), graph.parentWays(graph.entity(midpoint.edge[1])));
37668 parents.forEach(function (way) {
37669 for (var i = 0; i < way.nodes.length - 1; i++) {
37670 if (geoEdgeEqual([way.nodes[i], way.nodes[i + 1]], midpoint.edge)) {
37671 graph = graph.replace(graph.entity(way.id).addNode(node.id, i + 1)); // Add only one midpoint on doubled-back segments,
37672 // turning them into self-intersections.
37682 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
37683 function actionAddVertex(wayId, nodeId, index) {
37684 return function (graph) {
37685 return graph.replace(graph.entity(wayId).addNode(nodeId, index));
37689 function actionChangeMember(relationId, member, memberIndex) {
37690 return function (graph) {
37691 return graph.replace(graph.entity(relationId).updateMember(member, memberIndex));
37695 function actionChangePreset(entityID, oldPreset, newPreset, skipFieldDefaults) {
37696 return function action(graph) {
37697 var entity = graph.entity(entityID);
37698 var geometry = entity.geometry(graph);
37699 var tags = entity.tags; // preserve tags that the new preset might care about, if any
37701 if (oldPreset) tags = oldPreset.unsetTags(tags, geometry, newPreset && newPreset.addTags ? Object.keys(newPreset.addTags) : null);
37702 if (newPreset) tags = newPreset.setTags(tags, geometry, skipFieldDefaults);
37703 return graph.replace(entity.update({
37709 function actionChangeTags(entityId, tags) {
37710 return function (graph) {
37711 var entity = graph.entity(entityId);
37712 return graph.replace(entity.update({
37718 function osmNode() {
37719 if (!(this instanceof osmNode)) {
37720 return new osmNode().initialize(arguments);
37721 } else if (arguments.length) {
37722 this.initialize(arguments);
37725 osmEntity.node = osmNode;
37726 osmNode.prototype = Object.create(osmEntity.prototype);
37727 Object.assign(osmNode.prototype, {
37730 extent: function extent() {
37731 return new geoExtent(this.loc);
37733 geometry: function geometry(graph) {
37734 return graph["transient"](this, 'geometry', function () {
37735 return graph.isPoi(this) ? 'point' : 'vertex';
37738 move: function move(loc) {
37739 return this.update({
37743 isDegenerate: function isDegenerate() {
37744 return !(Array.isArray(this.loc) && this.loc.length === 2 && this.loc[0] >= -180 && this.loc[0] <= 180 && this.loc[1] >= -90 && this.loc[1] <= 90);
37746 // Inspect tags and geometry to determine which direction(s) this node/vertex points
37747 directions: function directions(resolver, projection) {
37749 var i; // which tag to use?
37751 if (this.isHighwayIntersection(resolver) && (this.tags.stop || '').toLowerCase() === 'all') {
37752 // all-way stop tag on a highway intersection
37755 // generic direction tag
37756 val = (this.tags.direction || '').toLowerCase(); // better suffix-style direction tag
37758 var re = /:direction$/i;
37759 var keys = Object.keys(this.tags);
37761 for (i = 0; i < keys.length; i++) {
37762 if (re.test(keys[i])) {
37763 val = this.tags[keys[i]].toLowerCase();
37769 if (val === '') return [];
37773 northnortheast: 22,
37781 eastsoutheast: 112,
37785 southsoutheast: 157,
37789 southsouthwest: 202,
37793 westsouthwest: 247,
37797 westnorthwest: 292,
37801 northnorthwest: 337,
37804 var values = val.split(';');
37806 values.forEach(function (v) {
37807 // swap cardinal for numeric directions
37808 if (cardinal[v] !== undefined) {
37810 } // numeric direction - just add to results
37813 if (v !== '' && !isNaN(+v)) {
37816 } // string direction - inspect parent ways
37819 var lookBackward = this.tags['traffic_sign:backward'] || v === 'backward' || v === 'both' || v === 'all';
37820 var lookForward = this.tags['traffic_sign:forward'] || v === 'forward' || v === 'both' || v === 'all';
37821 if (!lookForward && !lookBackward) return;
37823 resolver.parentWays(this).forEach(function (parent) {
37824 var nodes = parent.nodes;
37826 for (i = 0; i < nodes.length; i++) {
37827 if (nodes[i] === this.id) {
37828 // match current entity
37829 if (lookForward && i > 0) {
37830 nodeIds[nodes[i - 1]] = true; // look back to prev node
37833 if (lookBackward && i < nodes.length - 1) {
37834 nodeIds[nodes[i + 1]] = true; // look ahead to next node
37839 Object.keys(nodeIds).forEach(function (nodeId) {
37840 // +90 because geoAngle returns angle from X axis, not Y (north)
37841 results.push(geoAngle(this, resolver.entity(nodeId), projection) * (180 / Math.PI) + 90);
37844 return utilArrayUniq(results);
37846 isCrossing: function isCrossing() {
37847 return this.tags.highway === 'crossing' || this.tags.railway && this.tags.railway.indexOf('crossing') !== -1;
37849 isEndpoint: function isEndpoint(resolver) {
37850 return resolver["transient"](this, 'isEndpoint', function () {
37852 return resolver.parentWays(this).filter(function (parent) {
37853 return !parent.isClosed() && !!parent.affix(id);
37857 isConnected: function isConnected(resolver) {
37858 return resolver["transient"](this, 'isConnected', function () {
37859 var parents = resolver.parentWays(this);
37861 if (parents.length > 1) {
37862 // vertex is connected to multiple parent ways
37863 for (var i in parents) {
37864 if (parents[i].geometry(resolver) === 'line' && parents[i].hasInterestingTags()) return true;
37866 } else if (parents.length === 1) {
37867 var way = parents[0];
37868 var nodes = way.nodes.slice();
37870 if (way.isClosed()) {
37872 } // ignore connecting node if closed
37873 // return true if vertex appears multiple times (way is self intersecting)
37876 return nodes.indexOf(this.id) !== nodes.lastIndexOf(this.id);
37882 parentIntersectionWays: function parentIntersectionWays(resolver) {
37883 return resolver["transient"](this, 'parentIntersectionWays', function () {
37884 return resolver.parentWays(this).filter(function (parent) {
37885 return (parent.tags.highway || parent.tags.waterway || parent.tags.railway || parent.tags.aeroway) && parent.geometry(resolver) === 'line';
37889 isIntersection: function isIntersection(resolver) {
37890 return this.parentIntersectionWays(resolver).length > 1;
37892 isHighwayIntersection: function isHighwayIntersection(resolver) {
37893 return resolver["transient"](this, 'isHighwayIntersection', function () {
37894 return resolver.parentWays(this).filter(function (parent) {
37895 return parent.tags.highway && parent.geometry(resolver) === 'line';
37899 isOnAddressLine: function isOnAddressLine(resolver) {
37900 return resolver["transient"](this, 'isOnAddressLine', function () {
37901 return resolver.parentWays(this).filter(function (parent) {
37902 return parent.tags.hasOwnProperty('addr:interpolation') && parent.geometry(resolver) === 'line';
37906 asJXON: function asJXON(changeset_id) {
37909 '@id': this.osmId(),
37910 '@lon': this.loc[0],
37911 '@lat': this.loc[1],
37912 '@version': this.version || 0,
37913 tag: Object.keys(this.tags).map(function (k) {
37923 if (changeset_id) r.node['@changeset'] = changeset_id;
37926 asGeoJSON: function asGeoJSON() {
37929 coordinates: this.loc
37934 function actionCircularize(wayId, projection, maxAngle) {
37935 maxAngle = (maxAngle || 20) * Math.PI / 180;
37937 var action = function action(graph, t) {
37938 if (t === null || !isFinite(t)) t = 1;
37939 t = Math.min(Math.max(+t, 0), 1);
37940 var way = graph.entity(wayId);
37941 var origNodes = {};
37942 graph.childNodes(way).forEach(function (node) {
37943 if (!origNodes[node.id]) origNodes[node.id] = node;
37946 if (!way.isConvex(graph)) {
37947 graph = action.makeConvex(graph);
37950 var nodes = utilArrayUniq(graph.childNodes(way));
37951 var keyNodes = nodes.filter(function (n) {
37952 return graph.parentWays(n).length !== 1;
37954 var points = nodes.map(function (n) {
37955 return projection(n.loc);
37957 var keyPoints = keyNodes.map(function (n) {
37958 return projection(n.loc);
37960 var centroid = points.length === 2 ? geoVecInterp(points[0], points[1], 0.5) : d3_polygonCentroid(points);
37961 var radius = d3_median(points, function (p) {
37962 return geoVecLength(centroid, p);
37964 var sign = d3_polygonArea(points) > 0 ? 1 : -1;
37965 var ids, i, j, k; // we need at least two key nodes for the algorithm to work
37967 if (!keyNodes.length) {
37968 keyNodes = [nodes[0]];
37969 keyPoints = [points[0]];
37972 if (keyNodes.length === 1) {
37973 var index = nodes.indexOf(keyNodes[0]);
37974 var oppositeIndex = Math.floor((index + nodes.length / 2) % nodes.length);
37975 keyNodes.push(nodes[oppositeIndex]);
37976 keyPoints.push(points[oppositeIndex]);
37977 } // key points and nodes are those connected to the ways,
37978 // they are projected onto the circle, in between nodes are moved
37979 // to constant intervals between key nodes, extra in between nodes are
37980 // added if necessary.
37983 for (i = 0; i < keyPoints.length; i++) {
37984 var nextKeyNodeIndex = (i + 1) % keyNodes.length;
37985 var startNode = keyNodes[i];
37986 var endNode = keyNodes[nextKeyNodeIndex];
37987 var startNodeIndex = nodes.indexOf(startNode);
37988 var endNodeIndex = nodes.indexOf(endNode);
37989 var numberNewPoints = -1;
37990 var indexRange = endNodeIndex - startNodeIndex;
37991 var nearNodes = {};
37992 var inBetweenNodes = [];
37993 var startAngle, endAngle, totalAngle, eachAngle;
37994 var angle, loc, node, origNode;
37996 if (indexRange < 0) {
37997 indexRange += nodes.length;
37998 } // position this key node
38001 var distance = geoVecLength(centroid, keyPoints[i]) || 1e-4;
38002 keyPoints[i] = [centroid[0] + (keyPoints[i][0] - centroid[0]) / distance * radius, centroid[1] + (keyPoints[i][1] - centroid[1]) / distance * radius];
38003 loc = projection.invert(keyPoints[i]);
38004 node = keyNodes[i];
38005 origNode = origNodes[node.id];
38006 node = node.move(geoVecInterp(origNode.loc, loc, t));
38007 graph = graph.replace(node); // figure out the between delta angle we want to match to
38009 startAngle = Math.atan2(keyPoints[i][1] - centroid[1], keyPoints[i][0] - centroid[0]);
38010 endAngle = Math.atan2(keyPoints[nextKeyNodeIndex][1] - centroid[1], keyPoints[nextKeyNodeIndex][0] - centroid[0]);
38011 totalAngle = endAngle - startAngle; // detects looping around -pi/pi
38013 if (totalAngle * sign > 0) {
38014 totalAngle = -sign * (2 * Math.PI - Math.abs(totalAngle));
38019 eachAngle = totalAngle / (indexRange + numberNewPoints);
38020 } while (Math.abs(eachAngle) > maxAngle); // move existing nodes
38023 for (j = 1; j < indexRange; j++) {
38024 angle = startAngle + j * eachAngle;
38025 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]);
38026 node = nodes[(j + startNodeIndex) % nodes.length];
38027 origNode = origNodes[node.id];
38028 nearNodes[node.id] = angle;
38029 node = node.move(geoVecInterp(origNode.loc, loc, t));
38030 graph = graph.replace(node);
38031 } // add new in between nodes if necessary
38034 for (j = 0; j < numberNewPoints; j++) {
38035 angle = startAngle + (indexRange + j) * eachAngle;
38036 loc = projection.invert([centroid[0] + Math.cos(angle) * radius, centroid[1] + Math.sin(angle) * radius]); // choose a nearnode to use as the original
38038 var min = Infinity;
38040 for (var nodeId in nearNodes) {
38041 var nearAngle = nearNodes[nodeId];
38042 var dist = Math.abs(nearAngle - angle);
38046 origNode = origNodes[nodeId];
38051 loc: geoVecInterp(origNode.loc, loc, t)
38053 graph = graph.replace(node);
38054 nodes.splice(endNodeIndex + j, 0, node);
38055 inBetweenNodes.push(node.id);
38056 } // Check for other ways that share these keyNodes..
38057 // If keyNodes are adjacent in both ways,
38058 // we can add inBetweenNodes to that shared way too..
38061 if (indexRange === 1 && inBetweenNodes.length) {
38062 var startIndex1 = way.nodes.lastIndexOf(startNode.id);
38063 var endIndex1 = way.nodes.lastIndexOf(endNode.id);
38064 var wayDirection1 = endIndex1 - startIndex1;
38066 if (wayDirection1 < -1) {
38070 var parentWays = graph.parentWays(keyNodes[i]);
38072 for (j = 0; j < parentWays.length; j++) {
38073 var sharedWay = parentWays[j];
38074 if (sharedWay === way) continue;
38076 if (sharedWay.areAdjacent(startNode.id, endNode.id)) {
38077 var startIndex2 = sharedWay.nodes.lastIndexOf(startNode.id);
38078 var endIndex2 = sharedWay.nodes.lastIndexOf(endNode.id);
38079 var wayDirection2 = endIndex2 - startIndex2;
38080 var insertAt = endIndex2;
38082 if (wayDirection2 < -1) {
38086 if (wayDirection1 !== wayDirection2) {
38087 inBetweenNodes.reverse();
38088 insertAt = startIndex2;
38091 for (k = 0; k < inBetweenNodes.length; k++) {
38092 sharedWay = sharedWay.addNode(inBetweenNodes[k], insertAt + k);
38095 graph = graph.replace(sharedWay);
38099 } // update the way to have all the new nodes
38102 ids = nodes.map(function (n) {
38109 graph = graph.replace(way);
38113 action.makeConvex = function (graph) {
38114 var way = graph.entity(wayId);
38115 var nodes = utilArrayUniq(graph.childNodes(way));
38116 var points = nodes.map(function (n) {
38117 return projection(n.loc);
38119 var sign = d3_polygonArea(points) > 0 ? 1 : -1;
38120 var hull = d3_polygonHull(points);
38121 var i, j; // D3 convex hulls go counterclockwise..
38128 for (i = 0; i < hull.length - 1; i++) {
38129 var startIndex = points.indexOf(hull[i]);
38130 var endIndex = points.indexOf(hull[i + 1]);
38131 var indexRange = endIndex - startIndex;
38133 if (indexRange < 0) {
38134 indexRange += nodes.length;
38135 } // move interior nodes to the surface of the convex hull..
38138 for (j = 1; j < indexRange; j++) {
38139 var point = geoVecInterp(hull[i], hull[i + 1], j / indexRange);
38140 var node = nodes[(j + startIndex) % nodes.length].move(projection.invert(point));
38141 graph = graph.replace(node);
38148 action.disabled = function (graph) {
38149 if (!graph.entity(wayId).isClosed()) {
38150 return 'not_closed';
38151 } //disable when already circular
38154 var way = graph.entity(wayId);
38155 var nodes = utilArrayUniq(graph.childNodes(way));
38156 var points = nodes.map(function (n) {
38157 return projection(n.loc);
38159 var hull = d3_polygonHull(points);
38160 var epsilonAngle = Math.PI / 180;
38162 if (hull.length !== points.length || hull.length < 3) {
38166 var centroid = d3_polygonCentroid(points);
38167 var radius = geoVecLengthSquare(centroid, points[0]);
38168 var i, actualPoint; // compare distances between centroid and points
38170 for (i = 0; i < hull.length; i++) {
38171 actualPoint = hull[i];
38172 var actualDist = geoVecLengthSquare(actualPoint, centroid);
38173 var diff = Math.abs(actualDist - radius); //compare distances with epsilon-error (5%)
38175 if (diff > 0.05 * radius) {
38178 } //check if central angles are smaller than maxAngle
38181 for (i = 0; i < hull.length; i++) {
38182 actualPoint = hull[i];
38183 var nextPoint = hull[(i + 1) % hull.length];
38184 var startAngle = Math.atan2(actualPoint[1] - centroid[1], actualPoint[0] - centroid[0]);
38185 var endAngle = Math.atan2(nextPoint[1] - centroid[1], nextPoint[0] - centroid[0]);
38186 var angle = endAngle - startAngle;
38192 if (angle > Math.PI) {
38193 angle = 2 * Math.PI - angle;
38196 if (angle > maxAngle + epsilonAngle) {
38201 return 'already_circular';
38204 action.transitionable = true;
38208 function actionDeleteWay(wayID) {
38209 function canDeleteNode(node, graph) {
38210 // don't delete nodes still attached to ways or relations
38211 if (graph.parentWays(node).length || graph.parentRelations(node).length) return false;
38212 var geometries = osmNodeGeometriesForTags(node.tags); // don't delete if this node can be a standalone point
38214 if (geometries.point) return false; // delete if this node only be a vertex
38216 if (geometries.vertex) return true; // iD doesn't know if this should be a point or vertex,
38217 // so only delete if there are no interesting tags
38219 return !node.hasInterestingTags();
38222 var action = function action(graph) {
38223 var way = graph.entity(wayID);
38224 graph.parentRelations(way).forEach(function (parent) {
38225 parent = parent.removeMembersWithID(wayID);
38226 graph = graph.replace(parent);
38228 if (parent.isDegenerate()) {
38229 graph = actionDeleteRelation(parent.id)(graph);
38232 new Set(way.nodes).forEach(function (nodeID) {
38233 graph = graph.replace(way.removeNode(nodeID));
38234 var node = graph.entity(nodeID);
38236 if (canDeleteNode(node, graph)) {
38237 graph = graph.remove(node);
38240 return graph.remove(way);
38246 function actionDeleteMultiple(ids) {
38248 way: actionDeleteWay,
38249 node: actionDeleteNode,
38250 relation: actionDeleteRelation
38253 var action = function action(graph) {
38254 ids.forEach(function (id) {
38255 if (graph.hasEntity(id)) {
38256 // It may have been deleted already.
38257 graph = actions[graph.entity(id).type](id)(graph);
38266 function actionDeleteRelation(relationID, allowUntaggedMembers) {
38267 function canDeleteEntity(entity, graph) {
38268 return !graph.parentWays(entity).length && !graph.parentRelations(entity).length && !entity.hasInterestingTags() && !allowUntaggedMembers;
38271 var action = function action(graph) {
38272 var relation = graph.entity(relationID);
38273 graph.parentRelations(relation).forEach(function (parent) {
38274 parent = parent.removeMembersWithID(relationID);
38275 graph = graph.replace(parent);
38277 if (parent.isDegenerate()) {
38278 graph = actionDeleteRelation(parent.id)(graph);
38281 var memberIDs = utilArrayUniq(relation.members.map(function (m) {
38284 memberIDs.forEach(function (memberID) {
38285 graph = graph.replace(relation.removeMembersWithID(memberID));
38286 var entity = graph.entity(memberID);
38288 if (canDeleteEntity(entity, graph)) {
38289 graph = actionDeleteMultiple([memberID])(graph);
38292 return graph.remove(relation);
38298 function actionDeleteNode(nodeId) {
38299 var action = function action(graph) {
38300 var node = graph.entity(nodeId);
38301 graph.parentWays(node).forEach(function (parent) {
38302 parent = parent.removeNode(nodeId);
38303 graph = graph.replace(parent);
38305 if (parent.isDegenerate()) {
38306 graph = actionDeleteWay(parent.id)(graph);
38309 graph.parentRelations(node).forEach(function (parent) {
38310 parent = parent.removeMembersWithID(nodeId);
38311 graph = graph.replace(parent);
38313 if (parent.isDegenerate()) {
38314 graph = actionDeleteRelation(parent.id)(graph);
38317 return graph.remove(node);
38324 // First choose a node to be the survivor, with preference given
38325 // to an existing (not new) node.
38327 // Tags and relation memberships of of non-surviving nodes are merged
38328 // to the survivor.
38330 // This is the inverse of `iD.actionDisconnect`.
38333 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
38334 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
38337 function actionConnect(nodeIDs) {
38338 var action = function action(graph) {
38342 var i, j; // Choose a survivor node, prefer an existing (not new) node - #4974
38344 for (i = 0; i < nodeIDs.length; i++) {
38345 survivor = graph.entity(nodeIDs[i]);
38346 if (survivor.version) break; // found one
38347 } // Replace all non-surviving nodes with the survivor and merge tags.
38350 for (i = 0; i < nodeIDs.length; i++) {
38351 node = graph.entity(nodeIDs[i]);
38352 if (node.id === survivor.id) continue;
38353 parents = graph.parentWays(node);
38355 for (j = 0; j < parents.length; j++) {
38356 graph = graph.replace(parents[j].replaceNode(node.id, survivor.id));
38359 parents = graph.parentRelations(node);
38361 for (j = 0; j < parents.length; j++) {
38362 graph = graph.replace(parents[j].replaceMember(node, survivor));
38365 survivor = survivor.mergeTags(node.tags);
38366 graph = actionDeleteNode(node.id)(graph);
38369 graph = graph.replace(survivor); // find and delete any degenerate ways created by connecting adjacent vertices
38371 parents = graph.parentWays(survivor);
38373 for (i = 0; i < parents.length; i++) {
38374 if (parents[i].isDegenerate()) {
38375 graph = actionDeleteWay(parents[i].id)(graph);
38382 action.disabled = function (graph) {
38384 var restrictionIDs = [];
38387 var relations, relation, role;
38388 var i, j, k; // Choose a survivor node, prefer an existing (not new) node - #4974
38390 for (i = 0; i < nodeIDs.length; i++) {
38391 survivor = graph.entity(nodeIDs[i]);
38392 if (survivor.version) break; // found one
38393 } // 1. disable if the nodes being connected have conflicting relation roles
38396 for (i = 0; i < nodeIDs.length; i++) {
38397 node = graph.entity(nodeIDs[i]);
38398 relations = graph.parentRelations(node);
38400 for (j = 0; j < relations.length; j++) {
38401 relation = relations[j];
38402 role = relation.memberById(node.id).role || ''; // if this node is a via node in a restriction, remember for later
38404 if (relation.hasFromViaTo()) {
38405 restrictionIDs.push(relation.id);
38408 if (seen[relation.id] !== undefined && seen[relation.id] !== role) {
38411 seen[relation.id] = role;
38414 } // gather restrictions for parent ways
38417 for (i = 0; i < nodeIDs.length; i++) {
38418 node = graph.entity(nodeIDs[i]);
38419 var parents = graph.parentWays(node);
38421 for (j = 0; j < parents.length; j++) {
38422 var parent = parents[j];
38423 relations = graph.parentRelations(parent);
38425 for (k = 0; k < relations.length; k++) {
38426 relation = relations[k];
38428 if (relation.hasFromViaTo()) {
38429 restrictionIDs.push(relation.id);
38433 } // test restrictions
38436 restrictionIDs = utilArrayUniq(restrictionIDs);
38438 for (i = 0; i < restrictionIDs.length; i++) {
38439 relation = graph.entity(restrictionIDs[i]);
38440 if (!relation.isComplete(graph)) continue;
38441 var memberWays = relation.members.filter(function (m) {
38442 return m.type === 'way';
38443 }).map(function (m) {
38444 return graph.entity(m.id);
38446 memberWays = utilArrayUniq(memberWays);
38447 var f = relation.memberByRole('from');
38448 var t = relation.memberByRole('to');
38449 var isUturn = f.id === t.id; // 2a. disable if connection would damage a restriction
38450 // (a key node is a node at the junction of ways)
38460 for (j = 0; j < relation.members.length; j++) {
38461 collectNodes(relation.members[j], nodes);
38464 nodes.keyfrom = utilArrayUniq(nodes.keyfrom.filter(hasDuplicates));
38465 nodes.keyto = utilArrayUniq(nodes.keyto.filter(hasDuplicates));
38466 var filter = keyNodeFilter(nodes.keyfrom, nodes.keyto);
38467 nodes.from = nodes.from.filter(filter);
38468 nodes.via = nodes.via.filter(filter);
38469 nodes.to = nodes.to.filter(filter);
38470 var connectFrom = false;
38471 var connectVia = false;
38472 var connectTo = false;
38473 var connectKeyFrom = false;
38474 var connectKeyTo = false;
38476 for (j = 0; j < nodeIDs.length; j++) {
38477 var n = nodeIDs[j];
38479 if (nodes.from.indexOf(n) !== -1) {
38480 connectFrom = true;
38483 if (nodes.via.indexOf(n) !== -1) {
38487 if (nodes.to.indexOf(n) !== -1) {
38491 if (nodes.keyfrom.indexOf(n) !== -1) {
38492 connectKeyFrom = true;
38495 if (nodes.keyto.indexOf(n) !== -1) {
38496 connectKeyTo = true;
38500 if (connectFrom && connectTo && !isUturn) {
38501 return 'restriction';
38504 if (connectFrom && connectVia) {
38505 return 'restriction';
38508 if (connectTo && connectVia) {
38509 return 'restriction';
38510 } // connecting to a key node -
38511 // if both nodes are on a member way (i.e. part of the turn restriction),
38512 // the connecting node must be adjacent to the key node.
38515 if (connectKeyFrom || connectKeyTo) {
38516 if (nodeIDs.length !== 2) {
38517 return 'restriction';
38523 for (j = 0; j < memberWays.length; j++) {
38524 way = memberWays[j];
38526 if (way.contains(nodeIDs[0])) {
38530 if (way.contains(nodeIDs[1])) {
38536 // both nodes are part of the restriction
38539 for (j = 0; j < memberWays.length; j++) {
38540 way = memberWays[j];
38542 if (way.areAdjacent(n0, n1)) {
38549 return 'restriction';
38552 } // 2b. disable if nodes being connected will destroy a member way in a restriction
38553 // (to test, make a copy and try actually connecting the nodes)
38556 for (j = 0; j < memberWays.length; j++) {
38557 way = memberWays[j].update({}); // make copy
38559 for (k = 0; k < nodeIDs.length; k++) {
38560 if (nodeIDs[k] === survivor.id) continue;
38562 if (way.areAdjacent(nodeIDs[k], survivor.id)) {
38563 way = way.removeNode(nodeIDs[k]);
38565 way = way.replaceNode(nodeIDs[k], survivor.id);
38569 if (way.isDegenerate()) {
38570 return 'restriction';
38575 return false; // if a key node appears multiple times (indexOf !== lastIndexOf) it's a FROM-VIA or TO-VIA junction
38577 function hasDuplicates(n, i, arr) {
38578 return arr.indexOf(n) !== arr.lastIndexOf(n);
38581 function keyNodeFilter(froms, tos) {
38582 return function (n) {
38583 return froms.indexOf(n) === -1 && tos.indexOf(n) === -1;
38587 function collectNodes(member, collection) {
38588 var entity = graph.hasEntity(member.id);
38589 if (!entity) return;
38590 var role = member.role || '';
38592 if (!collection[role]) {
38593 collection[role] = [];
38596 if (member.type === 'node') {
38597 collection[role].push(member.id);
38599 if (role === 'via') {
38600 collection.keyfrom.push(member.id);
38601 collection.keyto.push(member.id);
38603 } else if (member.type === 'way') {
38604 collection[role].push.apply(collection[role], entity.nodes);
38606 if (role === 'from' || role === 'via') {
38607 collection.keyfrom.push(entity.first());
38608 collection.keyfrom.push(entity.last());
38611 if (role === 'to' || role === 'via') {
38612 collection.keyto.push(entity.first());
38613 collection.keyto.push(entity.last());
38622 function actionCopyEntities(ids, fromGraph) {
38625 var action = function action(graph) {
38626 ids.forEach(function (id) {
38627 fromGraph.entity(id).copy(fromGraph, _copies);
38630 for (var id in _copies) {
38631 graph = graph.replace(_copies[id]);
38637 action.copies = function () {
38644 function actionDeleteMember(relationId, memberIndex) {
38645 return function (graph) {
38646 var relation = graph.entity(relationId).removeMember(memberIndex);
38647 graph = graph.replace(relation);
38649 if (relation.isDegenerate()) {
38650 graph = actionDeleteRelation(relation.id)(graph);
38657 function actionDiscardTags(difference, discardTags) {
38658 discardTags = discardTags || {};
38659 return function (graph) {
38660 difference.modified().forEach(checkTags);
38661 difference.created().forEach(checkTags);
38664 function checkTags(entity) {
38665 var keys = Object.keys(entity.tags);
38666 var didDiscard = false;
38669 for (var i = 0; i < keys.length; i++) {
38672 if (discardTags[k] || !entity.tags[k]) {
38675 tags[k] = entity.tags[k];
38680 graph = graph.replace(entity.update({
38689 // Optionally, disconnect only the given ways.
38691 // For testing convenience, accepts an ID to assign to the (first) new node.
38692 // Normally, this will be undefined and the way will automatically
38693 // be assigned a new ID.
38695 // This is the inverse of `iD.actionConnect`.
38698 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
38699 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
38702 function actionDisconnect(nodeId, newNodeId) {
38705 var action = function action(graph) {
38706 var node = graph.entity(nodeId);
38707 var connections = action.connections(graph);
38708 connections.forEach(function (connection) {
38709 var way = graph.entity(connection.wayID);
38710 var newNode = osmNode({
38715 graph = graph.replace(newNode);
38717 if (connection.index === 0 && way.isArea()) {
38718 // replace shared node with shared node..
38719 graph = graph.replace(way.replaceNode(way.nodes[0], newNode.id));
38720 } else if (way.isClosed() && connection.index === way.nodes.length - 1) {
38721 // replace closing node with new new node..
38722 graph = graph.replace(way.unclose().addNode(newNode.id));
38724 // replace shared node with multiple new nodes..
38725 graph = graph.replace(way.updateNode(newNode.id, connection.index));
38731 action.connections = function (graph) {
38732 var candidates = [];
38733 var keeping = false;
38734 var parentWays = graph.parentWays(graph.entity(nodeId));
38737 for (var i = 0; i < parentWays.length; i++) {
38738 way = parentWays[i];
38740 if (wayIds && wayIds.indexOf(way.id) === -1) {
38745 if (way.isArea() && way.nodes[0] === nodeId) {
38751 for (var j = 0; j < way.nodes.length; j++) {
38752 waynode = way.nodes[j];
38754 if (waynode === nodeId) {
38755 if (way.isClosed() && parentWays.length > 1 && wayIds && wayIds.indexOf(way.id) !== -1 && j === way.nodes.length - 1) {
38768 return keeping ? candidates : candidates.slice(1);
38771 action.disabled = function (graph) {
38772 var connections = action.connections(graph);
38773 if (connections.length === 0) return 'not_connected';
38774 var parentWays = graph.parentWays(graph.entity(nodeId));
38775 var seenRelationIds = {};
38776 var sharedRelation;
38777 parentWays.forEach(function (way) {
38778 var relations = graph.parentRelations(way);
38779 relations.forEach(function (relation) {
38780 if (relation.id in seenRelationIds) {
38782 if (wayIds.indexOf(way.id) !== -1 || wayIds.indexOf(seenRelationIds[relation.id]) !== -1) {
38783 sharedRelation = relation;
38786 sharedRelation = relation;
38789 seenRelationIds[relation.id] = way.id;
38793 if (sharedRelation) return 'relation';
38796 action.limitWays = function (val) {
38797 if (!arguments.length) return wayIds;
38805 function actionExtract(entityID, projection) {
38806 var extractedNodeID;
38808 var action = function action(graph) {
38809 var entity = graph.entity(entityID);
38811 if (entity.type === 'node') {
38812 return extractFromNode(entity, graph);
38815 return extractFromWayOrRelation(entity, graph);
38818 function extractFromNode(node, graph) {
38819 extractedNodeID = node.id; // Create a new node to replace the one we will detach
38821 var replacement = osmNode({
38824 graph = graph.replace(replacement); // Process each way in turn, updating the graph as we go
38826 graph = graph.parentWays(node).reduce(function (accGraph, parentWay) {
38827 return accGraph.replace(parentWay.replaceNode(entityID, replacement.id));
38828 }, graph); // Process any relations too
38830 return graph.parentRelations(node).reduce(function (accGraph, parentRel) {
38831 return accGraph.replace(parentRel.replaceMember(node, replacement));
38835 function extractFromWayOrRelation(entity, graph) {
38836 var fromGeometry = entity.geometry(graph);
38837 var keysToCopyAndRetain = ['source', 'wheelchair'];
38838 var keysToRetain = ['area'];
38839 var buildingKeysToRetain = ['architect', 'building', 'height', 'layer'];
38840 var extractedLoc = d3_geoPath(projection).centroid(entity.asGeoJSON(graph));
38841 extractedLoc = extractedLoc && projection.invert(extractedLoc);
38843 if (!extractedLoc || !isFinite(extractedLoc[0]) || !isFinite(extractedLoc[1])) {
38844 extractedLoc = entity.extent(graph).center();
38847 var indoorAreaValues = {
38854 var isBuilding = entity.tags.building && entity.tags.building !== 'no' || entity.tags['building:part'] && entity.tags['building:part'] !== 'no';
38855 var isIndoorArea = fromGeometry === 'area' && entity.tags.indoor && indoorAreaValues[entity.tags.indoor];
38856 var entityTags = Object.assign({}, entity.tags); // shallow copy
38858 var pointTags = {};
38860 for (var key in entityTags) {
38861 if (entity.type === 'relation' && key === 'type') {
38865 if (keysToRetain.indexOf(key) !== -1) {
38870 // don't transfer building-related tags
38871 if (buildingKeysToRetain.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
38872 } // leave `indoor` tag on the area
38875 if (isIndoorArea && key === 'indoor') {
38877 } // copy the tag from the entity to the point
38880 pointTags[key] = entityTags[key]; // leave addresses and some other tags so they're on both features
38882 if (keysToCopyAndRetain.indexOf(key) !== -1 || key.match(/^addr:.{1,}/)) {
38884 } else if (isIndoorArea && key === 'level') {
38885 // leave `level` on both features
38887 } // remove the tag from the entity
38890 delete entityTags[key];
38893 if (!isBuilding && !isIndoorArea && fromGeometry === 'area') {
38894 // ensure that areas keep area geometry
38895 entityTags.area = 'yes';
38898 var replacement = osmNode({
38902 graph = graph.replace(replacement);
38903 extractedNodeID = replacement.id;
38904 return graph.replace(entity.update({
38909 action.getExtractedNodeID = function () {
38910 return extractedNodeID;
38917 // This is the inverse of `iD.actionSplit`.
38920 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
38921 // https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
38924 function actionJoin(ids) {
38925 function groupEntitiesByGeometry(graph) {
38926 var entities = ids.map(function (id) {
38927 return graph.entity(id);
38929 return Object.assign({
38931 }, utilArrayGroupBy(entities, function (entity) {
38932 return entity.geometry(graph);
38936 var action = function action(graph) {
38937 var ways = ids.map(graph.entity, graph); // if any of the ways are sided (e.g. coastline, cliff, kerb)
38938 // sort them first so they establish the overall order - #6033
38940 ways.sort(function (a, b) {
38941 var aSided = a.isSided();
38942 var bSided = b.isSided();
38943 return aSided && !bSided ? -1 : bSided && !aSided ? 1 : 0;
38944 }); // Prefer to keep an existing way.
38945 // if there are multiple existing ways, keep the oldest one
38946 // the oldest way is determined by the ID of the way
38948 var survivorID = (ways.filter(function (way) {
38949 return !way.isNew();
38950 }).sort(function (a, b) {
38951 return +a.osmId() - +b.osmId();
38952 })[0] || ways[0]).id;
38953 var sequences = osmJoinWays(ways, graph);
38954 var joined = sequences[0]; // We might need to reverse some of these ways before joining them. #4688
38955 // `joined.actions` property will contain any actions we need to apply.
38957 graph = sequences.actions.reduce(function (g, action) {
38960 var survivor = graph.entity(survivorID);
38961 survivor = survivor.update({
38962 nodes: joined.nodes.map(function (n) {
38966 graph = graph.replace(survivor);
38967 joined.forEach(function (way) {
38968 if (way.id === survivorID) return;
38969 graph.parentRelations(way).forEach(function (parent) {
38970 graph = graph.replace(parent.replaceMember(way, survivor));
38972 survivor = survivor.mergeTags(way.tags);
38973 graph = graph.replace(survivor);
38974 graph = actionDeleteWay(way.id)(graph);
38975 }); // Finds if the join created a single-member multipolygon,
38976 // and if so turns it into a basic area instead
38978 function checkForSimpleMultipolygon() {
38979 if (!survivor.isClosed()) return;
38980 var multipolygons = graph.parentMultipolygons(survivor).filter(function (multipolygon) {
38981 // find multipolygons where the survivor is the only member
38982 return multipolygon.members.length === 1;
38983 }); // skip if this is the single member of multiple multipolygons
38985 if (multipolygons.length !== 1) return;
38986 var multipolygon = multipolygons[0];
38988 for (var key in survivor.tags) {
38989 if (multipolygon.tags[key] && // don't collapse if tags cannot be cleanly merged
38990 multipolygon.tags[key] !== survivor.tags[key]) return;
38993 survivor = survivor.mergeTags(multipolygon.tags);
38994 graph = graph.replace(survivor);
38995 graph = actionDeleteRelation(multipolygon.id, true
38996 /* allow untagged members */
38998 var tags = Object.assign({}, survivor.tags);
39000 if (survivor.geometry(graph) !== 'area') {
39001 // ensure the feature persists as an area
39005 delete tags.type; // remove type=multipolygon
39007 survivor = survivor.update({
39010 graph = graph.replace(survivor);
39013 checkForSimpleMultipolygon();
39015 }; // Returns the number of nodes the resultant way is expected to have
39018 action.resultingWayNodesLength = function (graph) {
39019 return ids.reduce(function (count, id) {
39020 return count + graph.entity(id).nodes.length;
39021 }, 0) - ids.length - 1;
39024 action.disabled = function (graph) {
39025 var geometries = groupEntitiesByGeometry(graph);
39027 if (ids.length < 2 || ids.length !== geometries.line.length) {
39028 return 'not_eligible';
39031 var joined = osmJoinWays(ids.map(graph.entity, graph), graph);
39033 if (joined.length > 1) {
39034 return 'not_adjacent';
39037 var i; // All joined ways must belong to the same set of (non-restriction) relations.
39038 // Restriction relations have different logic, below, which allows some cases
39039 // this prohibits, and prohibits some cases this allows.
39041 var sortedParentRelations = function sortedParentRelations(id) {
39042 return graph.parentRelations(graph.entity(id)).filter(function (rel) {
39043 return !rel.isRestriction() && !rel.isConnectivity();
39044 }).sort(function (a, b) {
39045 return a.id - b.id;
39049 var relsA = sortedParentRelations(ids[0]);
39051 for (i = 1; i < ids.length; i++) {
39052 var relsB = sortedParentRelations(ids[i]);
39054 if (!utilArrayIdentical(relsA, relsB)) {
39055 return 'conflicting_relations';
39057 } // Loop through all combinations of path-pairs
39058 // to check potential intersections between all pairs
39061 for (i = 0; i < ids.length - 1; i++) {
39062 for (var j = i + 1; j < ids.length; j++) {
39063 var path1 = graph.childNodes(graph.entity(ids[i])).map(function (e) {
39066 var path2 = graph.childNodes(graph.entity(ids[j])).map(function (e) {
39069 var intersections = geoPathIntersections(path1, path2); // Check if intersections are just nodes lying on top of
39070 // each other/the line, as opposed to crossing it
39072 var common = utilArrayIntersection(joined[0].nodes.map(function (n) {
39073 return n.loc.toString();
39074 }), intersections.map(function (n) {
39075 return n.toString();
39078 if (common.length !== intersections.length) {
39079 return 'paths_intersect';
39084 var nodeIds = joined[0].nodes.map(function (n) {
39089 var conflicting = false;
39090 joined[0].forEach(function (way) {
39091 var parents = graph.parentRelations(way);
39092 parents.forEach(function (parent) {
39093 if ((parent.isRestriction() || parent.isConnectivity()) && parent.members.some(function (m) {
39094 return nodeIds.indexOf(m.id) >= 0;
39100 for (var k in way.tags) {
39101 if (!(k in tags)) {
39102 tags[k] = way.tags[k];
39103 } else if (tags[k] && osmIsInterestingTag(k) && tags[k] !== way.tags[k]) {
39104 conflicting = true;
39110 return relation.isRestriction() ? 'restriction' : 'connectivity';
39114 return 'conflicting_tags';
39121 function actionMerge(ids) {
39122 function groupEntitiesByGeometry(graph) {
39123 var entities = ids.map(function (id) {
39124 return graph.entity(id);
39126 return Object.assign({
39131 }, utilArrayGroupBy(entities, function (entity) {
39132 return entity.geometry(graph);
39136 var action = function action(graph) {
39137 var geometries = groupEntitiesByGeometry(graph);
39138 var target = geometries.area[0] || geometries.line[0];
39139 var points = geometries.point;
39140 points.forEach(function (point) {
39141 target = target.mergeTags(point.tags);
39142 graph = graph.replace(target);
39143 graph.parentRelations(point).forEach(function (parent) {
39144 graph = graph.replace(parent.replaceMember(point, target));
39146 var nodes = utilArrayUniq(graph.childNodes(target));
39147 var removeNode = point;
39149 for (var i = 0; i < nodes.length; i++) {
39150 var node = nodes[i];
39152 if (graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags()) {
39154 } // Found an uninteresting child node on the target way.
39155 // Move orig point into its place to preserve point's history. #3683
39158 graph = graph.replace(point.update({
39162 target = target.replaceNode(node.id, point.id);
39163 graph = graph.replace(target);
39168 graph = graph.remove(removeNode);
39171 if (target.tags.area === 'yes') {
39172 var tags = Object.assign({}, target.tags); // shallow copy
39176 if (osmTagSuggestingArea(tags)) {
39177 // remove the `area` tag if area geometry is now implied - #3851
39178 target = target.update({
39181 graph = graph.replace(target);
39188 action.disabled = function (graph) {
39189 var geometries = groupEntitiesByGeometry(graph);
39191 if (geometries.point.length === 0 || geometries.area.length + geometries.line.length !== 1 || geometries.relation.length !== 0) {
39192 return 'not_eligible';
39200 // 1. move all the nodes to a common location
39201 // 2. `actionConnect` them
39203 function actionMergeNodes(nodeIDs, loc) {
39204 // If there is a single "interesting" node, use that as the location.
39205 // Otherwise return the average location of all the nodes.
39206 function chooseLoc(graph) {
39207 if (!nodeIDs.length) return null;
39209 var interestingCount = 0;
39210 var interestingLoc;
39212 for (var i = 0; i < nodeIDs.length; i++) {
39213 var node = graph.entity(nodeIDs[i]);
39215 if (node.hasInterestingTags()) {
39216 interestingLoc = ++interestingCount === 1 ? node.loc : null;
39219 sum = geoVecAdd(sum, node.loc);
39222 return interestingLoc || geoVecScale(sum, 1 / nodeIDs.length);
39225 var action = function action(graph) {
39226 if (nodeIDs.length < 2) return graph;
39230 toLoc = chooseLoc(graph);
39233 for (var i = 0; i < nodeIDs.length; i++) {
39234 var node = graph.entity(nodeIDs[i]);
39236 if (node.loc !== toLoc) {
39237 graph = graph.replace(node.move(toLoc));
39241 return actionConnect(nodeIDs)(graph);
39244 action.disabled = function (graph) {
39245 if (nodeIDs.length < 2) return 'not_eligible';
39247 for (var i = 0; i < nodeIDs.length; i++) {
39248 var entity = graph.entity(nodeIDs[i]);
39249 if (entity.type !== 'node') return 'not_eligible';
39252 return actionConnect(nodeIDs).disabled(graph);
39258 function osmChangeset() {
39259 if (!(this instanceof osmChangeset)) {
39260 return new osmChangeset().initialize(arguments);
39261 } else if (arguments.length) {
39262 this.initialize(arguments);
39265 osmEntity.changeset = osmChangeset;
39266 osmChangeset.prototype = Object.create(osmEntity.prototype);
39267 Object.assign(osmChangeset.prototype, {
39269 extent: function extent() {
39270 return new geoExtent();
39272 geometry: function geometry() {
39273 return 'changeset';
39275 asJXON: function asJXON() {
39279 tag: Object.keys(this.tags).map(function (k) {
39291 // Generate [osmChange](http://wiki.openstreetmap.org/wiki/OsmChange)
39292 // XML. Returns a string.
39293 osmChangeJXON: function osmChangeJXON(changes) {
39294 var changeset_id = this.id;
39296 function nest(x, order) {
39299 for (var i = 0; i < x.length; i++) {
39300 var tagName = Object.keys(x[i])[0];
39301 if (!groups[tagName]) groups[tagName] = [];
39302 groups[tagName].push(x[i][tagName]);
39306 order.forEach(function (o) {
39307 if (groups[o]) ordered[o] = groups[o];
39310 } // sort relations in a changeset by dependencies
39313 function sort(changes) {
39314 // find a referenced relation in the current changeset
39315 function resolve(item) {
39316 return relations.find(function (relation) {
39317 return item.keyAttributes.type === 'relation' && item.keyAttributes.ref === relation['@id'];
39319 } // a new item is an item that has not been already processed
39322 function isNew(item) {
39323 return !sorted[item['@id']] && !processing.find(function (proc) {
39324 return proc['@id'] === item['@id'];
39328 var processing = [];
39330 var relations = changes.relation;
39331 if (!relations) return changes;
39333 for (var i = 0; i < relations.length; i++) {
39334 var relation = relations[i]; // skip relation if already sorted
39336 if (!sorted[relation['@id']]) {
39337 processing.push(relation);
39340 while (processing.length > 0) {
39341 var next = processing[0],
39342 deps = next.member.map(resolve).filter(Boolean).filter(isNew);
39344 if (deps.length === 0) {
39345 sorted[next['@id']] = next;
39346 processing.shift();
39348 processing = deps.concat(processing);
39353 changes.relation = Object.values(sorted);
39357 function rep(entity) {
39358 return entity.asJXON(changeset_id);
39364 '@generator': 'iD',
39365 'create': sort(nest(changes.created.map(rep), ['node', 'way', 'relation'])),
39366 'modify': nest(changes.modified.map(rep), ['node', 'way', 'relation']),
39367 'delete': Object.assign(nest(changes.deleted.map(rep), ['relation', 'way', 'node']), {
39373 asGeoJSON: function asGeoJSON() {
39378 function osmNote() {
39379 if (!(this instanceof osmNote)) {
39380 return new osmNote().initialize(arguments);
39381 } else if (arguments.length) {
39382 this.initialize(arguments);
39386 osmNote.id = function () {
39387 return osmNote.id.next--;
39390 osmNote.id.next = -1;
39391 Object.assign(osmNote.prototype, {
39393 initialize: function initialize(sources) {
39394 for (var i = 0; i < sources.length; ++i) {
39395 var source = sources[i];
39397 for (var prop in source) {
39398 if (Object.prototype.hasOwnProperty.call(source, prop)) {
39399 if (source[prop] === undefined) {
39402 this[prop] = source[prop];
39409 this.id = osmNote.id().toString();
39414 extent: function extent() {
39415 return new geoExtent(this.loc);
39417 update: function update(attrs) {
39418 return osmNote(this, attrs); // {v: 1 + (this.v || 0)}
39420 isNew: function isNew() {
39421 return this.id < 0;
39423 move: function move(loc) {
39424 return this.update({
39430 function osmRelation() {
39431 if (!(this instanceof osmRelation)) {
39432 return new osmRelation().initialize(arguments);
39433 } else if (arguments.length) {
39434 this.initialize(arguments);
39437 osmEntity.relation = osmRelation;
39438 osmRelation.prototype = Object.create(osmEntity.prototype);
39440 osmRelation.creationOrder = function (a, b) {
39441 var aId = parseInt(osmEntity.id.toOSM(a.id), 10);
39442 var bId = parseInt(osmEntity.id.toOSM(b.id), 10);
39443 if (aId < 0 || bId < 0) return aId - bId;
39447 Object.assign(osmRelation.prototype, {
39450 copy: function copy(resolver, copies) {
39451 if (copies[this.id]) return copies[this.id];
39452 var copy = osmEntity.prototype.copy.call(this, resolver, copies);
39453 var members = this.members.map(function (member) {
39454 return Object.assign({}, member, {
39455 id: resolver.entity(member.id).copy(resolver, copies).id
39458 copy = copy.update({
39461 copies[this.id] = copy;
39464 extent: function extent(resolver, memo) {
39465 return resolver["transient"](this, 'extent', function () {
39466 if (memo && memo[this.id]) return geoExtent();
39468 memo[this.id] = true;
39469 var extent = geoExtent();
39471 for (var i = 0; i < this.members.length; i++) {
39472 var member = resolver.hasEntity(this.members[i].id);
39475 extent._extend(member.extent(resolver, memo));
39482 geometry: function geometry(graph) {
39483 return graph["transient"](this, 'geometry', function () {
39484 return this.isMultipolygon() ? 'area' : 'relation';
39487 isDegenerate: function isDegenerate() {
39488 return this.members.length === 0;
39490 // Return an array of members, each extended with an 'index' property whose value
39491 // is the member index.
39492 indexedMembers: function indexedMembers() {
39493 var result = new Array(this.members.length);
39495 for (var i = 0; i < this.members.length; i++) {
39496 result[i] = Object.assign({}, this.members[i], {
39503 // Return the first member with the given role. A copy of the member object
39504 // is returned, extended with an 'index' property whose value is the member index.
39505 memberByRole: function memberByRole(role) {
39506 for (var i = 0; i < this.members.length; i++) {
39507 if (this.members[i].role === role) {
39508 return Object.assign({}, this.members[i], {
39514 // Same as memberByRole, but returns all members with the given role
39515 membersByRole: function membersByRole(role) {
39518 for (var i = 0; i < this.members.length; i++) {
39519 if (this.members[i].role === role) {
39520 result.push(Object.assign({}, this.members[i], {
39528 // Return the first member with the given id. A copy of the member object
39529 // is returned, extended with an 'index' property whose value is the member index.
39530 memberById: function memberById(id) {
39531 for (var i = 0; i < this.members.length; i++) {
39532 if (this.members[i].id === id) {
39533 return Object.assign({}, this.members[i], {
39539 // Return the first member with the given id and role. A copy of the member object
39540 // is returned, extended with an 'index' property whose value is the member index.
39541 memberByIdAndRole: function memberByIdAndRole(id, role) {
39542 for (var i = 0; i < this.members.length; i++) {
39543 if (this.members[i].id === id && this.members[i].role === role) {
39544 return Object.assign({}, this.members[i], {
39550 addMember: function addMember(member, index) {
39551 var members = this.members.slice();
39552 members.splice(index === undefined ? members.length : index, 0, member);
39553 return this.update({
39557 updateMember: function updateMember(member, index) {
39558 var members = this.members.slice();
39559 members.splice(index, 1, Object.assign({}, members[index], member));
39560 return this.update({
39564 removeMember: function removeMember(index) {
39565 var members = this.members.slice();
39566 members.splice(index, 1);
39567 return this.update({
39571 removeMembersWithID: function removeMembersWithID(id) {
39572 var members = this.members.filter(function (m) {
39573 return m.id !== id;
39575 return this.update({
39579 moveMember: function moveMember(fromIndex, toIndex) {
39580 var members = this.members.slice();
39581 members.splice(toIndex, 0, members.splice(fromIndex, 1)[0]);
39582 return this.update({
39586 // Wherever a member appears with id `needle.id`, replace it with a member
39587 // with id `replacement.id`, type `replacement.type`, and the original role,
39588 // By default, adding a duplicate member (by id and role) is prevented.
39589 // Return an updated relation.
39590 replaceMember: function replaceMember(needle, replacement, keepDuplicates) {
39591 if (!this.memberById(needle.id)) return this;
39594 for (var i = 0; i < this.members.length; i++) {
39595 var member = this.members[i];
39597 if (member.id !== needle.id) {
39598 members.push(member);
39599 } else if (keepDuplicates || !this.memberByIdAndRole(replacement.id, member.role)) {
39601 id: replacement.id,
39602 type: replacement.type,
39608 return this.update({
39612 asJXON: function asJXON(changeset_id) {
39615 '@id': this.osmId(),
39616 '@version': this.version || 0,
39617 member: this.members.map(function (member) {
39622 ref: osmEntity.id.toOSM(member.id)
39626 tag: Object.keys(this.tags).map(function (k) {
39637 if (changeset_id) {
39638 r.relation['@changeset'] = changeset_id;
39643 asGeoJSON: function asGeoJSON(resolver) {
39644 return resolver["transient"](this, 'GeoJSON', function () {
39645 if (this.isMultipolygon()) {
39647 type: 'MultiPolygon',
39648 coordinates: this.multipolygon(resolver)
39652 type: 'FeatureCollection',
39653 properties: this.tags,
39654 features: this.members.map(function (member) {
39655 return Object.assign({
39657 }, resolver.entity(member.id).asGeoJSON(resolver));
39663 area: function area(resolver) {
39664 return resolver["transient"](this, 'area', function () {
39665 return d3_geoArea(this.asGeoJSON(resolver));
39668 isMultipolygon: function isMultipolygon() {
39669 return this.tags.type === 'multipolygon';
39671 isComplete: function isComplete(resolver) {
39672 for (var i = 0; i < this.members.length; i++) {
39673 if (!resolver.hasEntity(this.members[i].id)) {
39680 hasFromViaTo: function hasFromViaTo() {
39681 return this.members.some(function (m) {
39682 return m.role === 'from';
39683 }) && this.members.some(function (m) {
39684 return m.role === 'via';
39685 }) && this.members.some(function (m) {
39686 return m.role === 'to';
39689 isRestriction: function isRestriction() {
39690 return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
39692 isValidRestriction: function isValidRestriction() {
39693 if (!this.isRestriction()) return false;
39694 var froms = this.members.filter(function (m) {
39695 return m.role === 'from';
39697 var vias = this.members.filter(function (m) {
39698 return m.role === 'via';
39700 var tos = this.members.filter(function (m) {
39701 return m.role === 'to';
39703 if (froms.length !== 1 && this.tags.restriction !== 'no_entry') return false;
39704 if (froms.some(function (m) {
39705 return m.type !== 'way';
39707 if (tos.length !== 1 && this.tags.restriction !== 'no_exit') return false;
39708 if (tos.some(function (m) {
39709 return m.type !== 'way';
39711 if (vias.length === 0) return false;
39712 if (vias.length > 1 && vias.some(function (m) {
39713 return m.type !== 'way';
39717 isConnectivity: function isConnectivity() {
39718 return !!(this.tags.type && this.tags.type.match(/^connectivity:?/));
39720 // Returns an array [A0, ... An], each Ai being an array of node arrays [Nds0, ... Ndsm],
39721 // where Nds0 is an outer ring and subsequent Ndsi's (if any i > 0) being inner rings.
39723 // This corresponds to the structure needed for rendering a multipolygon path using a
39724 // `evenodd` fill rule, as well as the structure of a GeoJSON MultiPolygon geometry.
39726 // In the case of invalid geometries, this function will still return a result which
39727 // includes the nodes of all way members, but some Nds may be unclosed and some inner
39728 // rings not matched with the intended outer ring.
39730 multipolygon: function multipolygon(resolver) {
39731 var outers = this.members.filter(function (m) {
39732 return 'outer' === (m.role || 'outer');
39734 var inners = this.members.filter(function (m) {
39735 return 'inner' === m.role;
39737 outers = osmJoinWays(outers, resolver);
39738 inners = osmJoinWays(inners, resolver);
39740 var sequenceToLineString = function sequenceToLineString(sequence) {
39741 if (sequence.nodes.length > 2 && sequence.nodes[0] !== sequence.nodes[sequence.nodes.length - 1]) {
39742 // close unclosed parts to ensure correct area rendering - #2945
39743 sequence.nodes.push(sequence.nodes[0]);
39746 return sequence.nodes.map(function (node) {
39751 outers = outers.map(sequenceToLineString);
39752 inners = inners.map(sequenceToLineString);
39753 var result = outers.map(function (o) {
39754 // Heuristic for detecting counterclockwise winding order. Assumes
39755 // that OpenStreetMap polygons are not hemisphere-spanning.
39756 return [d3_geoArea({
39759 }) > 2 * Math.PI ? o.reverse() : o];
39762 function findOuter(inner) {
39765 for (o = 0; o < outers.length; o++) {
39768 if (geoPolygonContainsPolygon(outer, inner)) {
39773 for (o = 0; o < outers.length; o++) {
39776 if (geoPolygonIntersectsPolygon(outer, inner, false)) {
39782 for (var i = 0; i < inners.length; i++) {
39783 var inner = inners[i];
39787 coordinates: [inner]
39788 }) < 2 * Math.PI) {
39789 inner = inner.reverse();
39792 var o = findOuter(inners[i]);
39794 if (o !== undefined) {
39795 result[o].push(inners[i]);
39797 result.push([inners[i]]); // Invalid geometry
39805 var QAItem = /*#__PURE__*/function () {
39806 function QAItem(loc, service, itemType, id, props) {
39807 _classCallCheck$1(this, QAItem);
39809 // Store required properties
39811 this.service = service.title;
39812 this.itemType = itemType; // All issues must have an ID for selection, use generic if none specified
39814 this.id = id ? id : "".concat(QAItem.id());
39815 this.update(props); // Some QA services have marker icons to differentiate issues
39817 if (service && typeof service.getIcon === 'function') {
39818 this.icon = service.getIcon(itemType);
39822 _createClass$1(QAItem, [{
39824 value: function update(props) {
39827 // You can't override this initial information
39828 var loc = this.loc,
39829 service = this.service,
39830 itemType = this.itemType,
39832 Object.keys(props).forEach(function (prop) {
39833 return _this[prop] = props[prop];
39836 this.service = service;
39837 this.itemType = itemType;
39840 } // Generic handling for newly created QAItems
39844 value: function id() {
39845 return this.nextId--;
39851 QAItem.nextId = -1;
39854 // Optionally, split only the given ways, if multiple ways share
39857 // This is the inverse of `iD.actionJoin`.
39859 // For testing convenience, accepts an ID to assign to the new way.
39860 // Normally, this will be undefined and the way will automatically
39861 // be assigned a new ID.
39864 // https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
39867 function actionSplit(nodeIds, newWayIds) {
39868 // accept single ID for backwards-compatiblity
39869 if (typeof nodeIds === 'string') nodeIds = [nodeIds];
39871 var _wayIDs; // the strategy for picking which way will have a new version and which way is newly created
39874 var _keepHistoryOn = 'longest'; // 'longest', 'first'
39875 // The IDs of the ways actually created by running this action
39877 var _createdWayIDs = [];
39879 function dist(graph, nA, nB) {
39880 var locA = graph.entity(nA).loc;
39881 var locB = graph.entity(nB).loc;
39882 var epsilon = 1e-6;
39883 return locA && locB ? geoSphericalDistance(locA, locB) : epsilon;
39884 } // If the way is closed, we need to search for a partner node
39885 // to split the way at.
39887 // The following looks for a node that is both far away from
39888 // the initial node in terms of way segment length and nearby
39889 // in terms of beeline-distance. This assures that areas get
39890 // split on the most "natural" points (independent of the number
39892 // For example: bone-shaped areas get split across their waist
39893 // line, circles across the diameter.
39896 function splitArea(nodes, idxA, graph) {
39897 var lengths = new Array(nodes.length);
39903 function wrap(index) {
39904 return utilWrap(index, nodes.length);
39905 } // calculate lengths
39910 for (i = wrap(idxA + 1); i !== idxA; i = wrap(i + 1)) {
39911 length += dist(graph, nodes[i], nodes[wrap(i - 1)]);
39912 lengths[i] = length;
39917 for (i = wrap(idxA - 1); i !== idxA; i = wrap(i - 1)) {
39918 length += dist(graph, nodes[i], nodes[wrap(i + 1)]);
39920 if (length < lengths[i]) {
39921 lengths[i] = length;
39923 } // determine best opposite node to split
39926 for (i = 0; i < nodes.length; i++) {
39927 var cost = lengths[i] / dist(graph, nodes[idxA], nodes[i]);
39938 function totalLengthBetweenNodes(graph, nodes) {
39939 var totalLength = 0;
39941 for (var i = 0; i < nodes.length - 1; i++) {
39942 totalLength += dist(graph, nodes[i], nodes[i + 1]);
39945 return totalLength;
39948 function split(graph, nodeId, wayA, newWayId) {
39949 var wayB = osmWay({
39952 }); // `wayB` is the NEW way
39954 var origNodes = wayA.nodes.slice();
39957 var isArea = wayA.isArea();
39958 var isOuter = osmIsOldMultipolygonOuterMember(wayA, graph);
39960 if (wayA.isClosed()) {
39961 var nodes = wayA.nodes.slice(0, -1);
39962 var idxA = nodes.indexOf(nodeId);
39963 var idxB = splitArea(nodes, idxA, graph);
39966 nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
39967 nodesB = nodes.slice(idxB, idxA + 1);
39969 nodesA = nodes.slice(idxA, idxB + 1);
39970 nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
39973 var idx = wayA.nodes.indexOf(nodeId, 1);
39974 nodesA = wayA.nodes.slice(0, idx + 1);
39975 nodesB = wayA.nodes.slice(idx);
39978 var lengthA = totalLengthBetweenNodes(graph, nodesA);
39979 var lengthB = totalLengthBetweenNodes(graph, nodesB);
39981 if (_keepHistoryOn === 'longest' && lengthB > lengthA) {
39982 // keep the history on the longer way, regardless of the node count
39983 wayA = wayA.update({
39986 wayB = wayB.update({
39989 var temp = lengthA;
39993 wayA = wayA.update({
39996 wayB = wayB.update({
40001 if (wayA.tags.step_count) {
40002 // divide up the the step count proportionally between the two ways
40003 var stepCount = parseFloat(wayA.tags.step_count);
40005 if (stepCount && // ensure a number
40006 isFinite(stepCount) && // ensure positive
40007 stepCount > 0 && // ensure integer
40008 Math.round(stepCount) === stepCount) {
40009 var tagsA = Object.assign({}, wayA.tags);
40010 var tagsB = Object.assign({}, wayB.tags);
40011 var ratioA = lengthA / (lengthA + lengthB);
40012 var countA = Math.round(stepCount * ratioA);
40013 tagsA.step_count = countA.toString();
40014 tagsB.step_count = (stepCount - countA).toString();
40015 wayA = wayA.update({
40018 wayB = wayB.update({
40024 graph = graph.replace(wayA);
40025 graph = graph.replace(wayB);
40026 graph.parentRelations(wayA).forEach(function (relation) {
40027 var member; // Turn restrictions - make sure:
40028 // 1. Splitting a FROM/TO way - only `wayA` OR `wayB` remains in relation
40029 // (whichever one is connected to the VIA node/ways)
40030 // 2. Splitting a VIA way - `wayB` remains in relation as a VIA way
40032 if (relation.hasFromViaTo()) {
40033 var f = relation.memberByRole('from');
40034 var v = relation.membersByRole('via');
40035 var t = relation.memberByRole('to');
40036 var i; // 1. split a FROM/TO
40038 if (f.id === wayA.id || t.id === wayA.id) {
40041 if (v.length === 1 && v[0].type === 'node') {
40043 keepB = wayB.contains(v[0].id);
40045 // check via way(s)
40046 for (i = 0; i < v.length; i++) {
40047 if (v[i].type === 'way') {
40048 var wayVia = graph.hasEntity(v[i].id);
40050 if (wayVia && utilArrayIntersection(wayB.nodes, wayVia.nodes).length) {
40059 relation = relation.replaceMember(wayA, wayB);
40060 graph = graph.replace(relation);
40061 } // 2. split a VIA
40064 for (i = 0; i < v.length; i++) {
40065 if (v[i].type === 'way' && v[i].id === wayA.id) {
40071 graph = actionAddMember(relation.id, member, v[i].index + 1)(graph);
40075 } // All other relations (Routes, Multipolygons, etc):
40076 // 1. Both `wayA` and `wayB` remain in the relation
40077 // 2. But must be inserted as a pair (see `actionAddMember` for details)
40080 if (relation === isOuter) {
40081 graph = graph.replace(relation.mergeTags(wayA.tags));
40082 graph = graph.replace(wayA.update({
40085 graph = graph.replace(wayB.update({
40093 role: relation.memberById(wayA.id).role
40096 originalID: wayA.id,
40097 insertedID: wayB.id,
40100 graph = actionAddMember(relation.id, member, undefined, insertPair)(graph);
40104 if (!isOuter && isArea) {
40105 var multipolygon = osmRelation({
40106 tags: Object.assign({}, wayA.tags, {
40107 type: 'multipolygon'
40119 graph = graph.replace(multipolygon);
40120 graph = graph.replace(wayA.update({
40123 graph = graph.replace(wayB.update({
40128 _createdWayIDs.push(wayB.id);
40133 var action = function action(graph) {
40134 _createdWayIDs = [];
40135 var newWayIndex = 0;
40137 for (var i = 0; i < nodeIds.length; i++) {
40138 var nodeId = nodeIds[i];
40139 var candidates = action.waysForNode(nodeId, graph);
40141 for (var j = 0; j < candidates.length; j++) {
40142 graph = split(graph, nodeId, candidates[j], newWayIds && newWayIds[newWayIndex]);
40150 action.getCreatedWayIDs = function () {
40151 return _createdWayIDs;
40154 action.waysForNode = function (nodeId, graph) {
40155 var node = graph.entity(nodeId);
40156 var splittableParents = graph.parentWays(node).filter(isSplittable);
40159 // If the ways to split aren't specified, only split the lines.
40160 // If there are no lines to split, split the areas.
40161 var hasLine = splittableParents.some(function (parent) {
40162 return parent.geometry(graph) === 'line';
40166 return splittableParents.filter(function (parent) {
40167 return parent.geometry(graph) === 'line';
40172 return splittableParents;
40174 function isSplittable(parent) {
40175 // If the ways to split are specified, ignore everything else.
40176 if (_wayIDs && _wayIDs.indexOf(parent.id) === -1) return false; // We can fake splitting closed ways at their endpoints...
40178 if (parent.isClosed()) return true; // otherwise, we can't split nodes at their endpoints.
40180 for (var i = 1; i < parent.nodes.length - 1; i++) {
40181 if (parent.nodes[i] === nodeId) return true;
40188 action.ways = function (graph) {
40189 return utilArrayUniq([].concat.apply([], nodeIds.map(function (nodeId) {
40190 return action.waysForNode(nodeId, graph);
40194 action.disabled = function (graph) {
40195 for (var i = 0; i < nodeIds.length; i++) {
40196 var nodeId = nodeIds[i];
40197 var candidates = action.waysForNode(nodeId, graph);
40199 if (candidates.length === 0 || _wayIDs && _wayIDs.length !== candidates.length) {
40200 return 'not_eligible';
40205 action.limitWays = function (val) {
40206 if (!arguments.length) return _wayIDs;
40211 action.keepHistoryOn = function (val) {
40212 if (!arguments.length) return _keepHistoryOn;
40213 _keepHistoryOn = val;
40220 function coreGraph(other, mutable) {
40221 if (!(this instanceof coreGraph)) return new coreGraph(other, mutable);
40223 if (other instanceof coreGraph) {
40224 var base = other.base();
40225 this.entities = Object.assign(Object.create(base.entities), other.entities);
40226 this._parentWays = Object.assign(Object.create(base.parentWays), other._parentWays);
40227 this._parentRels = Object.assign(Object.create(base.parentRels), other._parentRels);
40229 this.entities = Object.create({});
40230 this._parentWays = Object.create({});
40231 this._parentRels = Object.create({});
40232 this.rebase(other || [], [this]);
40235 this.transients = {};
40236 this._childNodes = {};
40237 this.frozen = !mutable;
40239 coreGraph.prototype = {
40240 hasEntity: function hasEntity(id) {
40241 return this.entities[id];
40243 entity: function entity(id) {
40244 var entity = this.entities[id]; //https://github.com/openstreetmap/iD/issues/3973#issuecomment-307052376
40247 entity = this.entities.__proto__[id]; // eslint-disable-line no-proto
40251 throw new Error('entity ' + id + ' not found');
40256 geometry: function geometry(id) {
40257 return this.entity(id).geometry(this);
40259 "transient": function transient(entity, key, fn) {
40260 var id = entity.id;
40261 var transients = this.transients[id] || (this.transients[id] = {});
40263 if (transients[key] !== undefined) {
40264 return transients[key];
40267 transients[key] = fn.call(entity);
40268 return transients[key];
40270 parentWays: function parentWays(entity) {
40271 var parents = this._parentWays[entity.id];
40275 parents.forEach(function (id) {
40276 result.push(this.entity(id));
40282 isPoi: function isPoi(entity) {
40283 var parents = this._parentWays[entity.id];
40284 return !parents || parents.size === 0;
40286 isShared: function isShared(entity) {
40287 var parents = this._parentWays[entity.id];
40288 return parents && parents.size > 1;
40290 parentRelations: function parentRelations(entity) {
40291 var parents = this._parentRels[entity.id];
40295 parents.forEach(function (id) {
40296 result.push(this.entity(id));
40302 parentMultipolygons: function parentMultipolygons(entity) {
40303 return this.parentRelations(entity).filter(function (relation) {
40304 return relation.isMultipolygon();
40307 childNodes: function childNodes(entity) {
40308 if (this._childNodes[entity.id]) return this._childNodes[entity.id];
40309 if (!entity.nodes) return [];
40312 for (var i = 0; i < entity.nodes.length; i++) {
40313 nodes[i] = this.entity(entity.nodes[i]);
40315 this._childNodes[entity.id] = nodes;
40316 return this._childNodes[entity.id];
40318 base: function base() {
40320 'entities': Object.getPrototypeOf(this.entities),
40321 'parentWays': Object.getPrototypeOf(this._parentWays),
40322 'parentRels': Object.getPrototypeOf(this._parentRels)
40325 // Unlike other graph methods, rebase mutates in place. This is because it
40326 // is used only during the history operation that merges newly downloaded
40327 // data into each state. To external consumers, it should appear as if the
40328 // graph always contained the newly downloaded data.
40329 rebase: function rebase(entities, stack, force) {
40330 var base = this.base();
40333 for (i = 0; i < entities.length; i++) {
40334 var entity = entities[i];
40335 if (!entity.visible || !force && base.entities[entity.id]) continue; // Merging data into the base graph
40337 base.entities[entity.id] = entity;
40339 this._updateCalculated(undefined, entity, base.parentWays, base.parentRels); // Restore provisionally-deleted nodes that are discovered to have an extant parent
40342 if (entity.type === 'way') {
40343 for (j = 0; j < entity.nodes.length; j++) {
40344 id = entity.nodes[j];
40346 for (k = 1; k < stack.length; k++) {
40347 var ents = stack[k].entities;
40349 if (ents.hasOwnProperty(id) && ents[id] === undefined) {
40357 for (i = 0; i < stack.length; i++) {
40358 stack[i]._updateRebased();
40361 _updateRebased: function _updateRebased() {
40362 var base = this.base();
40363 Object.keys(this._parentWays).forEach(function (child) {
40364 if (base.parentWays[child]) {
40365 base.parentWays[child].forEach(function (id) {
40366 if (!this.entities.hasOwnProperty(id)) {
40367 this._parentWays[child].add(id);
40372 Object.keys(this._parentRels).forEach(function (child) {
40373 if (base.parentRels[child]) {
40374 base.parentRels[child].forEach(function (id) {
40375 if (!this.entities.hasOwnProperty(id)) {
40376 this._parentRels[child].add(id);
40381 this.transients = {}; // this._childNodes is not updated, under the assumption that
40382 // ways are always downloaded with their child nodes.
40384 // Updates calculated properties (parentWays, parentRels) for the specified change
40385 _updateCalculated: function _updateCalculated(oldentity, entity, parentWays, parentRels) {
40386 parentWays = parentWays || this._parentWays;
40387 parentRels = parentRels || this._parentRels;
40388 var type = entity && entity.type || oldentity && oldentity.type;
40389 var removed, added, i;
40391 if (type === 'way') {
40392 // Update parentWays
40393 if (oldentity && entity) {
40394 removed = utilArrayDifference(oldentity.nodes, entity.nodes);
40395 added = utilArrayDifference(entity.nodes, oldentity.nodes);
40396 } else if (oldentity) {
40397 removed = oldentity.nodes;
40399 } else if (entity) {
40401 added = entity.nodes;
40404 for (i = 0; i < removed.length; i++) {
40405 // make a copy of prototype property, store as own property, and update..
40406 parentWays[removed[i]] = new Set(parentWays[removed[i]]);
40407 parentWays[removed[i]]["delete"](oldentity.id);
40410 for (i = 0; i < added.length; i++) {
40411 // make a copy of prototype property, store as own property, and update..
40412 parentWays[added[i]] = new Set(parentWays[added[i]]);
40413 parentWays[added[i]].add(entity.id);
40415 } else if (type === 'relation') {
40416 // Update parentRels
40417 // diff only on the IDs since the same entity can be a member multiple times with different roles
40418 var oldentityMemberIDs = oldentity ? oldentity.members.map(function (m) {
40421 var entityMemberIDs = entity ? entity.members.map(function (m) {
40425 if (oldentity && entity) {
40426 removed = utilArrayDifference(oldentityMemberIDs, entityMemberIDs);
40427 added = utilArrayDifference(entityMemberIDs, oldentityMemberIDs);
40428 } else if (oldentity) {
40429 removed = oldentityMemberIDs;
40431 } else if (entity) {
40433 added = entityMemberIDs;
40436 for (i = 0; i < removed.length; i++) {
40437 // make a copy of prototype property, store as own property, and update..
40438 parentRels[removed[i]] = new Set(parentRels[removed[i]]);
40439 parentRels[removed[i]]["delete"](oldentity.id);
40442 for (i = 0; i < added.length; i++) {
40443 // make a copy of prototype property, store as own property, and update..
40444 parentRels[added[i]] = new Set(parentRels[added[i]]);
40445 parentRels[added[i]].add(entity.id);
40449 replace: function replace(entity) {
40450 if (this.entities[entity.id] === entity) return this;
40451 return this.update(function () {
40452 this._updateCalculated(this.entities[entity.id], entity);
40454 this.entities[entity.id] = entity;
40457 remove: function remove(entity) {
40458 return this.update(function () {
40459 this._updateCalculated(entity, undefined);
40461 this.entities[entity.id] = undefined;
40464 revert: function revert(id) {
40465 var baseEntity = this.base().entities[id];
40466 var headEntity = this.entities[id];
40467 if (headEntity === baseEntity) return this;
40468 return this.update(function () {
40469 this._updateCalculated(headEntity, baseEntity);
40471 delete this.entities[id];
40474 update: function update() {
40475 var graph = this.frozen ? coreGraph(this, true) : this;
40477 for (var i = 0; i < arguments.length; i++) {
40478 arguments[i].call(graph, graph);
40481 if (this.frozen) graph.frozen = true;
40484 // Obliterates any existing entities
40485 load: function load(entities) {
40486 var base = this.base();
40487 this.entities = Object.create(base.entities);
40489 for (var i in entities) {
40490 this.entities[i] = entities[i];
40492 this._updateCalculated(base.entities[i], this.entities[i]);
40499 function osmTurn(turn) {
40500 if (!(this instanceof osmTurn)) {
40501 return new osmTurn(turn);
40504 Object.assign(this, turn);
40506 function osmIntersection(graph, startVertexId, maxDistance) {
40507 maxDistance = maxDistance || 30; // in meters
40509 var vgraph = coreGraph(); // virtual graph
40513 function memberOfRestriction(entity) {
40514 return graph.parentRelations(entity).some(function (r) {
40515 return r.isRestriction();
40519 function isRoad(way) {
40520 if (way.isArea() || way.isDegenerate()) return false;
40523 'motorway_link': true,
40525 'trunk_link': true,
40527 'primary_link': true,
40529 'secondary_link': true,
40531 'tertiary_link': true,
40532 'residential': true,
40533 'unclassified': true,
40534 'living_street': true,
40539 return roads[way.tags.highway];
40542 var startNode = graph.entity(startVertexId);
40543 var checkVertices = [startNode];
40546 var vertexIds = [];
40554 var parent; // `actions` will store whatever actions must be performed to satisfy
40555 // preconditions for adding a turn restriction to this intersection.
40556 // - Remove any existing degenerate turn restrictions (missing from/to, etc)
40557 // - Reverse oneways so that they are drawn in the forward direction
40558 // - Split ways on key vertices
40560 var actions = []; // STEP 1: walk the graph outwards from starting vertex to search
40561 // for more key vertices and ways to include in the intersection..
40563 while (checkVertices.length) {
40564 vertex = checkVertices.pop(); // check this vertex for parent ways that are roads
40566 checkWays = graph.parentWays(vertex);
40567 var hasWays = false;
40569 for (i = 0; i < checkWays.length; i++) {
40570 way = checkWays[i];
40571 if (!isRoad(way) && !memberOfRestriction(way)) continue;
40572 ways.push(way); // it's a road, or it's already in a turn restriction
40574 hasWays = true; // check the way's children for more key vertices
40576 nodes = utilArrayUniq(graph.childNodes(way));
40578 for (j = 0; j < nodes.length; j++) {
40580 if (node === vertex) continue; // same thing
40582 if (vertices.indexOf(node) !== -1) continue; // seen it already
40584 if (geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start
40585 // a key vertex will have parents that are also roads
40587 var hasParents = false;
40588 parents = graph.parentWays(node);
40590 for (k = 0; k < parents.length; k++) {
40591 parent = parents[k];
40592 if (parent === way) continue; // same thing
40594 if (ways.indexOf(parent) !== -1) continue; // seen it already
40596 if (!isRoad(parent)) continue; // not a road
40603 checkVertices.push(node);
40609 vertices.push(vertex);
40613 vertices = utilArrayUniq(vertices);
40614 ways = utilArrayUniq(ways); // STEP 2: Build a virtual graph containing only the entities in the intersection..
40615 // Everything done after this step should act on the virtual graph
40616 // Any actions that must be performed later to the main graph go in `actions` array
40618 ways.forEach(function (way) {
40619 graph.childNodes(way).forEach(function (node) {
40620 vgraph = vgraph.replace(node);
40622 vgraph = vgraph.replace(way);
40623 graph.parentRelations(way).forEach(function (relation) {
40624 if (relation.isRestriction()) {
40625 if (relation.isValidRestriction(graph)) {
40626 vgraph = vgraph.replace(relation);
40627 } else if (relation.isComplete(graph)) {
40628 actions.push(actionDeleteRelation(relation.id));
40632 }); // STEP 3: Force all oneways to be drawn in the forward direction
40634 ways.forEach(function (w) {
40635 var way = vgraph.entity(w.id);
40637 if (way.tags.oneway === '-1') {
40638 var action = actionReverse(way.id, {
40639 reverseOneway: true
40641 actions.push(action);
40642 vgraph = action(vgraph);
40644 }); // STEP 4: Split ways on key vertices
40646 var origCount = osmEntity.id.next.way;
40647 vertices.forEach(function (v) {
40648 // This is an odd way to do it, but we need to find all the ways that
40649 // will be split here, then split them one at a time to ensure that these
40650 // actions can be replayed on the main graph exactly in the same order.
40651 // (It is unintuitive, but the order of ways returned from graph.parentWays()
40652 // is arbitrary, depending on how the main graph and vgraph were built)
40653 var splitAll = actionSplit([v.id]).keepHistoryOn('first');
40655 if (!splitAll.disabled(vgraph)) {
40656 splitAll.ways(vgraph).forEach(function (way) {
40657 var splitOne = actionSplit([v.id]).limitWays([way.id]).keepHistoryOn('first');
40658 actions.push(splitOne);
40659 vgraph = splitOne(vgraph);
40662 }); // In here is where we should also split the intersection at nearby junction.
40663 // for https://github.com/mapbox/iD-internal/issues/31
40664 // nearbyVertices.forEach(function(v) {
40666 // Reasons why we reset the way id count here:
40667 // 1. Continuity with way ids created by the splits so that we can replay
40668 // these actions later if the user decides to create a turn restriction
40669 // 2. Avoids churning way ids just by hovering over a vertex
40670 // and displaying the turn restriction editor
40672 osmEntity.id.next.way = origCount; // STEP 5: Update arrays to point to vgraph entities
40674 vertexIds = vertices.map(function (v) {
40679 vertexIds.forEach(function (id) {
40680 var vertex = vgraph.entity(id);
40681 var parents = vgraph.parentWays(vertex);
40682 vertices.push(vertex);
40683 ways = ways.concat(parents);
40685 vertices = utilArrayUniq(vertices);
40686 ways = utilArrayUniq(ways);
40687 vertexIds = vertices.map(function (v) {
40690 wayIds = ways.map(function (w) {
40692 }); // STEP 6: Update the ways with some metadata that will be useful for
40693 // walking the intersection graph later and rendering turn arrows.
40695 function withMetadata(way, vertexIds) {
40696 var __oneWay = way.isOneWay(); // which affixes are key vertices?
40699 var __first = vertexIds.indexOf(way.first()) !== -1;
40701 var __last = vertexIds.indexOf(way.last()) !== -1; // what roles is this way eligible for?
40704 var __via = __first && __last;
40706 var __from = __first && !__oneWay || __last;
40708 var __to = __first || __last && !__oneWay;
40710 return way.update({
40721 wayIds.forEach(function (id) {
40722 var way = withMetadata(vgraph.entity(id), vertexIds);
40723 vgraph = vgraph.replace(way);
40725 }); // STEP 7: Simplify - This is an iterative process where we:
40726 // 1. Find trivial vertices with only 2 parents
40727 // 2. trim off the leaf way from those vertices and remove from vgraph
40730 var removeWayIds = [];
40731 var removeVertexIds = [];
40735 checkVertices = vertexIds.slice();
40737 for (i = 0; i < checkVertices.length; i++) {
40738 var vertexId = checkVertices[i];
40739 vertex = vgraph.hasEntity(vertexId);
40742 if (vertexIds.indexOf(vertexId) !== -1) {
40743 vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40746 removeVertexIds.push(vertexId);
40750 parents = vgraph.parentWays(vertex);
40752 if (parents.length < 3) {
40753 if (vertexIds.indexOf(vertexId) !== -1) {
40754 vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40758 if (parents.length === 2) {
40759 // vertex with 2 parents is trivial
40760 var a = parents[0];
40761 var b = parents[1];
40762 var aIsLeaf = a && !a.__via;
40763 var bIsLeaf = b && !b.__via;
40764 var leaf, survivor;
40766 if (aIsLeaf && !bIsLeaf) {
40769 } else if (!aIsLeaf && bIsLeaf) {
40774 if (leaf && survivor) {
40775 survivor = withMetadata(survivor, vertexIds); // update survivor way
40777 vgraph = vgraph.replace(survivor).remove(leaf); // update graph
40779 removeWayIds.push(leaf.id);
40784 parents = vgraph.parentWays(vertex);
40786 if (parents.length < 2) {
40787 // vertex is no longer a key vertex
40788 if (vertexIds.indexOf(vertexId) !== -1) {
40789 vertexIds.splice(vertexIds.indexOf(vertexId), 1); // stop checking this one
40792 removeVertexIds.push(vertexId);
40796 if (parents.length < 1) {
40797 // vertex is no longer attached to anything
40798 vgraph = vgraph.remove(vertex);
40801 } while (keepGoing);
40803 vertices = vertices.filter(function (vertex) {
40804 return removeVertexIds.indexOf(vertex.id) === -1;
40805 }).map(function (vertex) {
40806 return vgraph.entity(vertex.id);
40808 ways = ways.filter(function (way) {
40809 return removeWayIds.indexOf(way.id) === -1;
40810 }).map(function (way) {
40811 return vgraph.entity(way.id);
40812 }); // OK! Here is our intersection..
40814 var intersection = {
40817 vertices: vertices,
40819 }; // Get all the valid turns through this intersection given a starting way id.
40820 // This operates on the virtual graph for everything.
40822 // Basically, walk through all possible paths from starting way,
40823 // honoring the existing turn restrictions as we go (watch out for loops!)
40825 // For each path found, generate and return a `osmTurn` datastructure.
40828 intersection.turns = function (fromWayId, maxViaWay) {
40829 if (!fromWayId) return [];
40830 if (!maxViaWay) maxViaWay = 0;
40831 var vgraph = intersection.graph;
40832 var keyVertexIds = intersection.vertices.map(function (v) {
40835 var start = vgraph.entity(fromWayId);
40836 if (!start || !(start.__from || start.__via)) return []; // maxViaWay=0 from-*-to (0 vias)
40837 // maxViaWay=1 from-*-via-*-to (1 via max)
40838 // maxViaWay=2 from-*-via-*-via-*-to (2 vias max)
40840 var maxPathLength = maxViaWay * 2 + 3;
40843 return turns; // traverse the intersection graph and find all the valid paths
40845 function step(entity, currPath, currRestrictions, matchedRestriction) {
40846 currPath = (currPath || []).slice(); // shallow copy
40848 if (currPath.length >= maxPathLength) return;
40849 currPath.push(entity.id);
40850 currRestrictions = (currRestrictions || []).slice(); // shallow copy
40854 if (entity.type === 'node') {
40855 var parents = vgraph.parentWays(entity);
40856 var nextWays = []; // which ways can we step into?
40858 for (i = 0; i < parents.length; i++) {
40859 var way = parents[i]; // if next way is a oneway incoming to this vertex, skip
40861 if (way.__oneWay && way.nodes[0] !== entity.id) continue; // if we have seen it before (allowing for an initial u-turn), skip
40863 if (currPath.indexOf(way.id) !== -1 && currPath.length >= 3) continue; // Check all "current" restrictions (where we've already walked the `FROM`)
40865 var restrict = null;
40867 for (j = 0; j < currRestrictions.length; j++) {
40868 var restriction = currRestrictions[j];
40869 var f = restriction.memberByRole('from');
40870 var v = restriction.membersByRole('via');
40871 var t = restriction.memberByRole('to');
40872 var isOnly = /^only_/.test(restriction.tags.restriction); // Does the current path match this turn restriction?
40874 var matchesFrom = f.id === fromWayId;
40875 var matchesViaTo = false;
40876 var isAlongOnlyPath = false;
40878 if (t.id === way.id) {
40880 if (v.length === 1 && v[0].type === 'node') {
40882 matchesViaTo = v[0].id === entity.id && (matchesFrom && currPath.length === 2 || !matchesFrom && currPath.length > 2);
40884 // match all VIA ways
40887 for (k = 2; k < currPath.length; k += 2) {
40888 // k = 2 skips FROM
40889 pathVias.push(currPath[k]); // (path goes way-node-way...)
40892 var restrictionVias = [];
40894 for (k = 0; k < v.length; k++) {
40895 if (v[k].type === 'way') {
40896 restrictionVias.push(v[k].id);
40900 var diff = utilArrayDifference(pathVias, restrictionVias);
40901 matchesViaTo = !diff.length;
40903 } else if (isOnly) {
40904 for (k = 0; k < v.length; k++) {
40905 // way doesn't match TO, but is one of the via ways along the path of an "only"
40906 if (v[k].type === 'way' && v[k].id === way.id) {
40907 isAlongOnlyPath = true;
40913 if (matchesViaTo) {
40916 id: restriction.id,
40917 direct: matchesFrom,
40924 id: restriction.id,
40925 direct: matchesFrom,
40932 // indirect - caused by a different nearby restriction
40933 if (isAlongOnlyPath) {
40935 id: restriction.id,
40941 } else if (isOnly) {
40943 id: restriction.id,
40950 } // stop looking if we find a "direct" restriction (matching FROM, VIA, TO)
40953 if (restrict && restrict.direct) break;
40962 nextWays.forEach(function (nextWay) {
40963 step(nextWay.way, currPath, currRestrictions, nextWay.restrict);
40966 // entity.type === 'way'
40967 if (currPath.length >= 3) {
40968 // this is a "complete" path..
40969 var turnPath = currPath.slice(); // shallow copy
40970 // an indirect restriction - only include the partial path (starting at FROM)
40972 if (matchedRestriction && matchedRestriction.direct === false) {
40973 for (i = 0; i < turnPath.length; i++) {
40974 if (turnPath[i] === matchedRestriction.from) {
40975 turnPath = turnPath.slice(i);
40981 var turn = pathToTurn(turnPath);
40984 if (matchedRestriction) {
40985 turn.restrictionID = matchedRestriction.id;
40986 turn.no = matchedRestriction.no;
40987 turn.only = matchedRestriction.only;
40988 turn.direct = matchedRestriction.direct;
40991 turns.push(osmTurn(turn));
40994 if (currPath[0] === currPath[2]) return; // if we made a u-turn - stop here
40997 if (matchedRestriction && matchedRestriction.end) return; // don't advance any further
40998 // which nodes can we step into?
41000 var n1 = vgraph.entity(entity.first());
41001 var n2 = vgraph.entity(entity.last());
41002 var dist = geoSphericalDistance(n1.loc, n2.loc);
41003 var nextNodes = [];
41005 if (currPath.length > 1) {
41006 if (dist > maxDistance) return; // the next node is too far
41008 if (!entity.__via) return; // this way is a leaf / can't be a via
41011 if (!entity.__oneWay && // bidirectional..
41012 keyVertexIds.indexOf(n1.id) !== -1 && // key vertex..
41013 currPath.indexOf(n1.id) === -1) {
41014 // haven't seen it yet..
41015 nextNodes.push(n1); // can advance to first node
41018 if (keyVertexIds.indexOf(n2.id) !== -1 && // key vertex..
41019 currPath.indexOf(n2.id) === -1) {
41020 // haven't seen it yet..
41021 nextNodes.push(n2); // can advance to last node
41024 nextNodes.forEach(function (nextNode) {
41025 // gather restrictions FROM this way
41026 var fromRestrictions = vgraph.parentRelations(entity).filter(function (r) {
41027 if (!r.isRestriction()) return false;
41028 var f = r.memberByRole('from');
41029 if (!f || f.id !== entity.id) return false;
41030 var isOnly = /^only_/.test(r.tags.restriction);
41031 if (!isOnly) return true; // `only_` restrictions only matter along the direction of the VIA - #4849
41033 var isOnlyVia = false;
41034 var v = r.membersByRole('via');
41036 if (v.length === 1 && v[0].type === 'node') {
41038 isOnlyVia = v[0].id === nextNode.id;
41041 for (var i = 0; i < v.length; i++) {
41042 if (v[i].type !== 'way') continue;
41043 var viaWay = vgraph.entity(v[i].id);
41045 if (viaWay.first() === nextNode.id || viaWay.last() === nextNode.id) {
41054 step(nextNode, currPath, currRestrictions.concat(fromRestrictions), false);
41057 } // assumes path is alternating way-node-way of odd length
41060 function pathToTurn(path) {
41061 if (path.length < 3) return;
41062 var fromWayId, fromNodeId, fromVertexId;
41063 var toWayId, toNodeId, toVertexId;
41064 var viaWayIds, viaNodeId, isUturn;
41065 fromWayId = path[0];
41066 toWayId = path[path.length - 1];
41068 if (path.length === 3 && fromWayId === toWayId) {
41070 var way = vgraph.entity(fromWayId);
41071 if (way.__oneWay) return null;
41073 viaNodeId = fromVertexId = toVertexId = path[1];
41074 fromNodeId = toNodeId = adjacentNode(fromWayId, viaNodeId);
41077 fromVertexId = path[1];
41078 fromNodeId = adjacentNode(fromWayId, fromVertexId);
41079 toVertexId = path[path.length - 2];
41080 toNodeId = adjacentNode(toWayId, toVertexId);
41082 if (path.length === 3) {
41083 viaNodeId = path[1];
41085 viaWayIds = path.filter(function (entityId) {
41086 return entityId[0] === 'w';
41088 viaWayIds = viaWayIds.slice(1, viaWayIds.length - 1); // remove first, last
41093 key: path.join('_'),
41098 vertex: fromVertexId
41112 function adjacentNode(wayId, affixId) {
41113 var nodes = vgraph.entity(wayId).nodes;
41114 return affixId === nodes[0] ? nodes[1] : nodes[nodes.length - 2];
41119 return intersection;
41121 function osmInferRestriction(graph, turn, projection) {
41122 var fromWay = graph.entity(turn.from.way);
41123 var fromNode = graph.entity(turn.from.node);
41124 var fromVertex = graph.entity(turn.from.vertex);
41125 var toWay = graph.entity(turn.to.way);
41126 var toNode = graph.entity(turn.to.node);
41127 var toVertex = graph.entity(turn.to.vertex);
41128 var fromOneWay = fromWay.tags.oneway === 'yes';
41129 var toOneWay = toWay.tags.oneway === 'yes';
41130 var angle = (geoAngle(fromVertex, fromNode, projection) - geoAngle(toVertex, toNode, projection)) * 180 / Math.PI;
41132 while (angle < 0) {
41136 if (fromNode === toNode) {
41137 return 'no_u_turn';
41140 if ((angle < 23 || angle > 336) && fromOneWay && toOneWay) {
41141 return 'no_u_turn'; // wider tolerance for u-turn if both ways are oneway
41144 if ((angle < 40 || angle > 319) && fromOneWay && toOneWay && turn.from.vertex !== turn.to.vertex) {
41145 return 'no_u_turn'; // even wider tolerance for u-turn if there is a via way (from !== to)
41149 return 'no_right_turn';
41153 return 'no_left_turn';
41156 return 'no_straight_on';
41159 function actionMergePolygon(ids, newRelationId) {
41160 function groupEntities(graph) {
41161 var entities = ids.map(function (id) {
41162 return graph.entity(id);
41164 var geometryGroups = utilArrayGroupBy(entities, function (entity) {
41165 if (entity.type === 'way' && entity.isClosed()) {
41166 return 'closedWay';
41167 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
41168 return 'multipolygon';
41173 return Object.assign({
41177 }, geometryGroups);
41180 var action = function action(graph) {
41181 var entities = groupEntities(graph); // An array representing all the polygons that are part of the multipolygon.
41183 // Each element is itself an array of objects with an id property, and has a
41184 // locs property which is an array of the locations forming the polygon.
41186 var polygons = entities.multipolygon.reduce(function (polygons, m) {
41187 return polygons.concat(osmJoinWays(m.members, graph));
41188 }, []).concat(entities.closedWay.map(function (d) {
41192 member.nodes = graph.childNodes(d);
41194 })); // contained is an array of arrays of boolean values,
41195 // where contained[j][k] is true iff the jth way is
41196 // contained by the kth way.
41198 var contained = polygons.map(function (w, i) {
41199 return polygons.map(function (d, n) {
41200 if (i === n) return null;
41201 return geoPolygonContainsPolygon(d.nodes.map(function (n) {
41203 }), w.nodes.map(function (n) {
41207 }); // Sort all polygons as either outer or inner ways
41212 while (polygons.length) {
41213 extractUncontained(polygons);
41214 polygons = polygons.filter(isContained);
41215 contained = contained.filter(isContained).map(filterContained);
41218 function isContained(d, i) {
41219 return contained[i].some(function (val) {
41224 function filterContained(d) {
41225 return d.filter(isContained);
41228 function extractUncontained(polygons) {
41229 polygons.forEach(function (d, i) {
41230 if (!isContained(d, i)) {
41231 d.forEach(function (member) {
41235 role: outer ? 'outer' : 'inner'
41241 } // Move all tags to one relation
41244 var relation = entities.multipolygon[0] || osmRelation({
41247 type: 'multipolygon'
41250 entities.multipolygon.slice(1).forEach(function (m) {
41251 relation = relation.mergeTags(m.tags);
41252 graph = graph.remove(m);
41254 entities.closedWay.forEach(function (way) {
41255 function isThisOuter(m) {
41256 return m.id === way.id && m.role !== 'inner';
41259 if (members.some(isThisOuter)) {
41260 relation = relation.mergeTags(way.tags);
41261 graph = graph.replace(way.update({
41266 return graph.replace(relation.update({
41268 tags: utilObjectOmit(relation.tags, ['area'])
41272 action.disabled = function (graph) {
41273 var entities = groupEntities(graph);
41275 if (entities.other.length > 0 || entities.closedWay.length + entities.multipolygon.length < 2) {
41276 return 'not_eligible';
41279 if (!entities.multipolygon.every(function (r) {
41280 return r.isComplete(graph);
41282 return 'incomplete_relation';
41285 if (!entities.multipolygon.length) {
41286 var sharedMultipolygons = [];
41287 entities.closedWay.forEach(function (way, i) {
41289 sharedMultipolygons = graph.parentMultipolygons(way);
41291 sharedMultipolygons = utilArrayIntersection(sharedMultipolygons, graph.parentMultipolygons(way));
41294 sharedMultipolygons = sharedMultipolygons.filter(function (relation) {
41295 return relation.members.length === entities.closedWay.length;
41298 if (sharedMultipolygons.length) {
41299 // don't create a new multipolygon if it'd be redundant
41300 return 'not_eligible';
41302 } else if (entities.closedWay.some(function (way) {
41303 return utilArrayIntersection(graph.parentMultipolygons(way), entities.multipolygon).length;
41305 // don't add a way to a multipolygon again if it's already a member
41306 return 'not_eligible';
41313 var DESCRIPTORS = descriptors;
41314 var objectDefinePropertyModule = objectDefineProperty;
41315 var regExpFlags = regexpFlags$1;
41316 var fails$4 = fails$N;
41318 var FORCED$2 = DESCRIPTORS && fails$4(function () {
41319 // eslint-disable-next-line es/no-object-getownpropertydescriptor -- safe
41320 return Object.getOwnPropertyDescriptor(RegExp.prototype, 'flags').get.call({ dotAll: true, sticky: true }) !== 'sy';
41323 // `RegExp.prototype.flags` getter
41324 // https://tc39.es/ecma262/#sec-get-regexp.prototype.flags
41325 if (FORCED$2) objectDefinePropertyModule.f(RegExp.prototype, 'flags', {
41326 configurable: true,
41330 var fastDeepEqual = function equal(a, b) {
41331 if (a === b) return true;
41333 if (a && b && _typeof(a) == 'object' && _typeof(b) == 'object') {
41334 if (a.constructor !== b.constructor) return false;
41335 var length, i, keys;
41337 if (Array.isArray(a)) {
41339 if (length != b.length) return false;
41341 for (i = length; i-- !== 0;) {
41342 if (!equal(a[i], b[i])) return false;
41348 if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
41349 if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
41350 if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
41351 keys = Object.keys(a);
41352 length = keys.length;
41353 if (length !== Object.keys(b).length) return false;
41355 for (i = length; i-- !== 0;) {
41356 if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
41359 for (i = length; i-- !== 0;) {
41361 if (!equal(a[key], b[key])) return false;
41365 } // true if both NaN, false otherwise
41368 return a !== a && b !== b;
41371 // J. W. Hunt and M. D. McIlroy, An algorithm for differential buffer
41372 // comparison, Bell Telephone Laboratories CSTR #41 (1976)
41373 // http://www.cs.dartmouth.edu/~doug/
41374 // https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
41376 // Expects two arrays, finds longest common sequence
41378 function LCS(buffer1, buffer2) {
41379 var equivalenceClasses = {};
41381 for (var j = 0; j < buffer2.length; j++) {
41382 var item = buffer2[j];
41384 if (equivalenceClasses[item]) {
41385 equivalenceClasses[item].push(j);
41387 equivalenceClasses[item] = [j];
41396 var candidates = [NULLRESULT];
41398 for (var i = 0; i < buffer1.length; i++) {
41399 var _item = buffer1[i];
41400 var buffer2indices = equivalenceClasses[_item] || [];
41402 var c = candidates[0];
41404 for (var jx = 0; jx < buffer2indices.length; jx++) {
41405 var _j = buffer2indices[jx];
41408 for (s = r; s < candidates.length; s++) {
41409 if (candidates[s].buffer2index < _j && (s === candidates.length - 1 || candidates[s + 1].buffer2index > _j)) {
41414 if (s < candidates.length) {
41415 var newCandidate = {
41418 chain: candidates[s]
41421 if (r === candidates.length) {
41422 candidates.push(c);
41430 if (r === candidates.length) {
41431 break; // no point in examining further (j)s
41437 } // At this point, we know the LCS: it's in the reverse of the
41438 // linked-list through .chain of candidates[candidates.length - 1].
41441 return candidates[candidates.length - 1];
41442 } // We apply the LCS to build a 'comm'-style picture of the
41443 // offsets and lengths of mismatched chunks in the input
41444 // buffers. This is used by diff3MergeRegions.
41447 function diffIndices(buffer1, buffer2) {
41448 var lcs = LCS(buffer1, buffer2);
41450 var tail1 = buffer1.length;
41451 var tail2 = buffer2.length;
41453 for (var candidate = lcs; candidate !== null; candidate = candidate.chain) {
41454 var mismatchLength1 = tail1 - candidate.buffer1index - 1;
41455 var mismatchLength2 = tail2 - candidate.buffer2index - 1;
41456 tail1 = candidate.buffer1index;
41457 tail2 = candidate.buffer2index;
41459 if (mismatchLength1 || mismatchLength2) {
41461 buffer1: [tail1 + 1, mismatchLength1],
41462 buffer1Content: buffer1.slice(tail1 + 1, tail1 + 1 + mismatchLength1),
41463 buffer2: [tail2 + 1, mismatchLength2],
41464 buffer2Content: buffer2.slice(tail2 + 1, tail2 + 1 + mismatchLength2)
41471 } // We apply the LCS to build a JSON representation of a
41472 // independently derived from O, returns a fairly complicated
41473 // internal representation of merge decisions it's taken. The
41474 // interested reader may wish to consult
41476 // Sanjeev Khanna, Keshav Kunal, and Benjamin C. Pierce.
41477 // 'A Formal Investigation of ' In Arvind and Prasad,
41478 // editors, Foundations of Software Technology and Theoretical
41479 // Computer Science (FSTTCS), December 2007.
41481 // (http://www.cis.upenn.edu/~bcpierce/papers/diff3-short.pdf)
41485 function diff3MergeRegions(a, o, b) {
41486 // "hunks" are array subsets where `a` or `b` are different from `o`
41487 // https://www.gnu.org/software/diffutils/manual/html_node/diff3-Hunks.html
41490 function addHunk(h, ab) {
41493 oStart: h.buffer1[0],
41494 oLength: h.buffer1[1],
41495 // length of o to remove
41496 abStart: h.buffer2[0],
41497 abLength: h.buffer2[1] // length of a/b to insert
41498 // abContent: (ab === 'a' ? a : b).slice(h.buffer2[0], h.buffer2[0] + h.buffer2[1])
41503 diffIndices(o, a).forEach(function (item) {
41504 return addHunk(item, 'a');
41506 diffIndices(o, b).forEach(function (item) {
41507 return addHunk(item, 'b');
41509 hunks.sort(function (x, y) {
41510 return x.oStart - y.oStart;
41513 var currOffset = 0;
41515 function advanceTo(endOffset) {
41516 if (endOffset > currOffset) {
41520 bufferStart: currOffset,
41521 bufferLength: endOffset - currOffset,
41522 bufferContent: o.slice(currOffset, endOffset)
41524 currOffset = endOffset;
41528 while (hunks.length) {
41529 var hunk = hunks.shift();
41530 var regionStart = hunk.oStart;
41531 var regionEnd = hunk.oStart + hunk.oLength;
41532 var regionHunks = [hunk];
41533 advanceTo(regionStart); // Try to pull next overlapping hunk into this region
41535 while (hunks.length) {
41536 var nextHunk = hunks[0];
41537 var nextHunkStart = nextHunk.oStart;
41538 if (nextHunkStart > regionEnd) break; // no overlap
41540 regionEnd = Math.max(regionEnd, nextHunkStart + nextHunk.oLength);
41541 regionHunks.push(hunks.shift());
41544 if (regionHunks.length === 1) {
41545 // Only one hunk touches this region, meaning that there is no conflict here.
41546 // Either `a` or `b` is inserting into a region of `o` unchanged by the other.
41547 if (hunk.abLength > 0) {
41548 var buffer = hunk.ab === 'a' ? a : b;
41552 bufferStart: hunk.abStart,
41553 bufferLength: hunk.abLength,
41554 bufferContent: buffer.slice(hunk.abStart, hunk.abStart + hunk.abLength)
41558 // A true a/b conflict. Determine the bounds involved from `a`, `o`, and `b`.
41559 // Effectively merge all the `a` hunks into one giant hunk, then do the
41560 // same for the `b` hunks; then, correct for skew in the regions of `o`
41561 // that each side changed, and report appropriate spans for the three sides.
41563 a: [a.length, -1, o.length, -1],
41564 b: [b.length, -1, o.length, -1]
41567 while (regionHunks.length) {
41568 hunk = regionHunks.shift();
41569 var oStart = hunk.oStart;
41570 var oEnd = oStart + hunk.oLength;
41571 var abStart = hunk.abStart;
41572 var abEnd = abStart + hunk.abLength;
41573 var _b = bounds[hunk.ab];
41574 _b[0] = Math.min(abStart, _b[0]);
41575 _b[1] = Math.max(abEnd, _b[1]);
41576 _b[2] = Math.min(oStart, _b[2]);
41577 _b[3] = Math.max(oEnd, _b[3]);
41580 var aStart = bounds.a[0] + (regionStart - bounds.a[2]);
41581 var aEnd = bounds.a[1] + (regionEnd - bounds.a[3]);
41582 var bStart = bounds.b[0] + (regionStart - bounds.b[2]);
41583 var bEnd = bounds.b[1] + (regionEnd - bounds.b[3]);
41587 aLength: aEnd - aStart,
41588 aContent: a.slice(aStart, aEnd),
41589 oStart: regionStart,
41590 oLength: regionEnd - regionStart,
41591 oContent: o.slice(regionStart, regionEnd),
41593 bLength: bEnd - bStart,
41594 bContent: b.slice(bStart, bEnd)
41596 results.push(result);
41599 currOffset = regionEnd;
41602 advanceTo(o.length);
41604 } // Applies the output of diff3MergeRegions to actually
41605 // construct the merged buffer; the returned result alternates
41606 // between 'ok' and 'conflict' blocks.
41607 // A "false conflict" is where `a` and `b` both change the same from `o`
41610 function diff3Merge(a, o, b, options) {
41612 excludeFalseConflicts: true,
41613 stringSeparator: /\s+/
41615 options = Object.assign(defaults, options);
41616 var aString = typeof a === 'string';
41617 var oString = typeof o === 'string';
41618 var bString = typeof b === 'string';
41619 if (aString) a = a.split(options.stringSeparator);
41620 if (oString) o = o.split(options.stringSeparator);
41621 if (bString) b = b.split(options.stringSeparator);
41623 var regions = diff3MergeRegions(a, o, b);
41626 function flushOk() {
41627 if (okBuffer.length) {
41636 function isFalseConflict(a, b) {
41637 if (a.length !== b.length) return false;
41639 for (var i = 0; i < a.length; i++) {
41640 if (a[i] !== b[i]) return false;
41646 regions.forEach(function (region) {
41647 if (region.stable) {
41650 (_okBuffer = okBuffer).push.apply(_okBuffer, _toConsumableArray(region.bufferContent));
41652 if (options.excludeFalseConflicts && isFalseConflict(region.aContent, region.bContent)) {
41655 (_okBuffer2 = okBuffer).push.apply(_okBuffer2, _toConsumableArray(region.aContent));
41660 a: region.aContent,
41661 aIndex: region.aStart,
41662 o: region.oContent,
41663 oIndex: region.oStart,
41664 b: region.bContent,
41665 bIndex: region.bStart
41675 function actionMergeRemoteChanges(id, localGraph, remoteGraph, discardTags, formatUser) {
41676 discardTags = discardTags || {};
41677 var _option = 'safe'; // 'safe', 'force_local', 'force_remote'
41679 var _conflicts = [];
41682 return typeof formatUser === 'function' ? formatUser(d) : d;
41685 function mergeLocation(remote, target) {
41686 function pointEqual(a, b) {
41687 var epsilon = 1e-6;
41688 return Math.abs(a[0] - b[0]) < epsilon && Math.abs(a[1] - b[1]) < epsilon;
41691 if (_option === 'force_local' || pointEqual(target.loc, remote.loc)) {
41695 if (_option === 'force_remote') {
41696 return target.update({
41701 _conflicts.push(_t('merge_remote_changes.conflict.location', {
41702 user: user(remote.user)
41708 function mergeNodes(base, remote, target) {
41709 if (_option === 'force_local' || fastDeepEqual(target.nodes, remote.nodes)) {
41713 if (_option === 'force_remote') {
41714 return target.update({
41715 nodes: remote.nodes
41719 var ccount = _conflicts.length;
41720 var o = base.nodes || [];
41721 var a = target.nodes || [];
41722 var b = remote.nodes || [];
41724 var hunks = diff3Merge(a, o, b, {
41725 excludeFalseConflicts: true
41728 for (var i = 0; i < hunks.length; i++) {
41729 var hunk = hunks[i];
41732 nodes.push.apply(nodes, hunk.ok);
41734 // for all conflicts, we can assume c.a !== c.b
41735 // because `diff3Merge` called with `true` option to exclude false conflicts..
41736 var c = hunk.conflict;
41738 if (fastDeepEqual(c.o, c.a)) {
41739 // only changed remotely
41740 nodes.push.apply(nodes, c.b);
41741 } else if (fastDeepEqual(c.o, c.b)) {
41742 // only changed locally
41743 nodes.push.apply(nodes, c.a);
41745 // changed both locally and remotely
41746 _conflicts.push(_t('merge_remote_changes.conflict.nodelist', {
41747 user: user(remote.user)
41755 return _conflicts.length === ccount ? target.update({
41760 function mergeChildren(targetWay, children, updates, graph) {
41761 function isUsed(node, targetWay) {
41762 var hasInterestingParent = graph.parentWays(node).some(function (way) {
41763 return way.id !== targetWay.id;
41765 return node.hasInterestingTags() || hasInterestingParent || graph.parentRelations(node).length > 0;
41768 var ccount = _conflicts.length;
41770 for (var i = 0; i < children.length; i++) {
41771 var id = children[i];
41772 var node = graph.hasEntity(id); // remove unused childNodes..
41774 if (targetWay.nodes.indexOf(id) === -1) {
41775 if (node && !isUsed(node, targetWay)) {
41776 updates.removeIds.push(id);
41780 } // restore used childNodes..
41783 var local = localGraph.hasEntity(id);
41784 var remote = remoteGraph.hasEntity(id);
41787 if (_option === 'force_remote' && remote && remote.visible) {
41788 updates.replacements.push(remote);
41789 } else if (_option === 'force_local' && local) {
41790 target = osmEntity(local);
41793 target = target.update({
41794 version: remote.version
41798 updates.replacements.push(target);
41799 } else if (_option === 'safe' && local && remote && local.version !== remote.version) {
41800 target = osmEntity(local, {
41801 version: remote.version
41804 if (remote.visible) {
41805 target = mergeLocation(remote, target);
41807 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
41808 user: user(remote.user)
41812 if (_conflicts.length !== ccount) break;
41813 updates.replacements.push(target);
41820 function updateChildren(updates, graph) {
41821 for (var i = 0; i < updates.replacements.length; i++) {
41822 graph = graph.replace(updates.replacements[i]);
41825 if (updates.removeIds.length) {
41826 graph = actionDeleteMultiple(updates.removeIds)(graph);
41832 function mergeMembers(remote, target) {
41833 if (_option === 'force_local' || fastDeepEqual(target.members, remote.members)) {
41837 if (_option === 'force_remote') {
41838 return target.update({
41839 members: remote.members
41843 _conflicts.push(_t('merge_remote_changes.conflict.memberlist', {
41844 user: user(remote.user)
41850 function mergeTags(base, remote, target) {
41851 if (_option === 'force_local' || fastDeepEqual(target.tags, remote.tags)) {
41855 if (_option === 'force_remote') {
41856 return target.update({
41861 var ccount = _conflicts.length;
41862 var o = base.tags || {};
41863 var a = target.tags || {};
41864 var b = remote.tags || {};
41865 var keys = utilArrayUnion(utilArrayUnion(Object.keys(o), Object.keys(a)), Object.keys(b)).filter(function (k) {
41866 return !discardTags[k];
41868 var tags = Object.assign({}, a); // shallow copy
41870 var changed = false;
41872 for (var i = 0; i < keys.length; i++) {
41875 if (o[k] !== b[k] && a[k] !== b[k]) {
41876 // changed remotely..
41877 if (o[k] !== a[k]) {
41878 // changed locally..
41879 _conflicts.push(_t('merge_remote_changes.conflict.tags', {
41883 user: user(remote.user)
41886 // unchanged locally, accept remote change..
41887 if (b.hasOwnProperty(k)) {
41898 return changed && _conflicts.length === ccount ? target.update({
41901 } // `graph.base()` is the common ancestor of the two graphs.
41902 // `localGraph` contains user's edits up to saving
41903 // `remoteGraph` contains remote edits to modified nodes
41904 // `graph` must be a descendent of `localGraph` and may include
41905 // some conflict resolution actions performed on it.
41907 // --- ... --- `localGraph` -- ... -- `graph`
41909 // `graph.base()` --- ... --- `remoteGraph`
41913 var action = function action(graph) {
41918 var base = graph.base().entities[id];
41919 var local = localGraph.entity(id);
41920 var remote = remoteGraph.entity(id);
41921 var target = osmEntity(local, {
41922 version: remote.version
41923 }); // delete/undelete
41925 if (!remote.visible) {
41926 if (_option === 'force_remote') {
41927 return actionDeleteMultiple([id])(graph);
41928 } else if (_option === 'force_local') {
41929 if (target.type === 'way') {
41930 target = mergeChildren(target, utilArrayUniq(local.nodes), updates, graph);
41931 graph = updateChildren(updates, graph);
41934 return graph.replace(target);
41936 _conflicts.push(_t('merge_remote_changes.conflict.deleted', {
41937 user: user(remote.user)
41940 return graph; // do nothing
41945 if (target.type === 'node') {
41946 target = mergeLocation(remote, target);
41947 } else if (target.type === 'way') {
41948 // pull in any child nodes that may not be present locally..
41949 graph.rebase(remoteGraph.childNodes(remote), [graph], false);
41950 target = mergeNodes(base, remote, target);
41951 target = mergeChildren(target, utilArrayUnion(local.nodes, remote.nodes), updates, graph);
41952 } else if (target.type === 'relation') {
41953 target = mergeMembers(remote, target);
41956 target = mergeTags(base, remote, target);
41958 if (!_conflicts.length) {
41959 graph = updateChildren(updates, graph).replace(target);
41965 action.withOption = function (opt) {
41970 action.conflicts = function () {
41977 // https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MoveNodeAction.as
41979 function actionMove(moveIDs, tryDelta, projection, cache) {
41980 var _delta = tryDelta;
41982 function setupCache(graph) {
41983 function canMove(nodeID) {
41984 // Allow movement of any node that is in the selectedIDs list..
41985 if (moveIDs.indexOf(nodeID) !== -1) return true; // Allow movement of a vertex where 2 ways meet..
41987 var parents = graph.parentWays(graph.entity(nodeID));
41988 if (parents.length < 3) return true; // Restrict movement of a vertex where >2 ways meet, unless all parentWays are moving too..
41990 var parentsMoving = parents.every(function (way) {
41991 return cache.moving[way.id];
41993 if (!parentsMoving) delete cache.moving[nodeID];
41994 return parentsMoving;
41997 function cacheEntities(ids) {
41998 for (var i = 0; i < ids.length; i++) {
42000 if (cache.moving[id]) continue;
42001 cache.moving[id] = true;
42002 var entity = graph.hasEntity(id);
42003 if (!entity) continue;
42005 if (entity.type === 'node') {
42006 cache.nodes.push(id);
42007 cache.startLoc[id] = entity.loc;
42008 } else if (entity.type === 'way') {
42009 cache.ways.push(id);
42010 cacheEntities(entity.nodes);
42012 cacheEntities(entity.members.map(function (member) {
42019 function cacheIntersections(ids) {
42020 function isEndpoint(way, id) {
42021 return !way.isClosed() && !!way.affix(id);
42024 for (var i = 0; i < ids.length; i++) {
42025 var id = ids[i]; // consider only intersections with 1 moved and 1 unmoved way.
42027 var childNodes = graph.childNodes(graph.entity(id));
42029 for (var j = 0; j < childNodes.length; j++) {
42030 var node = childNodes[j];
42031 var parents = graph.parentWays(node);
42032 if (parents.length !== 2) continue;
42033 var moved = graph.entity(id);
42034 var unmoved = null;
42036 for (var k = 0; k < parents.length; k++) {
42037 var way = parents[k];
42039 if (!cache.moving[way.id]) {
42045 if (!unmoved) continue; // exclude ways that are overly connected..
42047 if (utilArrayIntersection(moved.nodes, unmoved.nodes).length > 2) continue;
42048 if (moved.isArea() || unmoved.isArea()) continue;
42049 cache.intersections.push({
42052 unmovedId: unmoved.id,
42053 movedIsEP: isEndpoint(moved, node.id),
42054 unmovedIsEP: isEndpoint(unmoved, node.id)
42066 cache.intersections = [];
42067 cache.replacedVertex = {};
42068 cache.startLoc = {};
42071 cacheEntities(moveIDs);
42072 cacheIntersections(cache.ways);
42073 cache.nodes = cache.nodes.filter(canMove);
42076 } // Place a vertex where the moved vertex used to be, to preserve way shape..
42085 // * node '*' added to preserve shape
42087 // / b ---- e way `b,e` moved here:
42094 function replaceMovedVertex(nodeId, wayId, graph, delta) {
42095 var way = graph.entity(wayId);
42096 var moved = graph.entity(nodeId);
42097 var movedIndex = way.nodes.indexOf(nodeId);
42098 var len, prevIndex, nextIndex;
42100 if (way.isClosed()) {
42101 len = way.nodes.length - 1;
42102 prevIndex = (movedIndex + len - 1) % len;
42103 nextIndex = (movedIndex + len + 1) % len;
42105 len = way.nodes.length;
42106 prevIndex = movedIndex - 1;
42107 nextIndex = movedIndex + 1;
42110 var prev = graph.hasEntity(way.nodes[prevIndex]);
42111 var next = graph.hasEntity(way.nodes[nextIndex]); // Don't add orig vertex at endpoint..
42113 if (!prev || !next) return graph;
42114 var key = wayId + '_' + nodeId;
42115 var orig = cache.replacedVertex[key];
42119 cache.replacedVertex[key] = orig;
42120 cache.startLoc[orig.id] = cache.startLoc[nodeId];
42126 start = projection(cache.startLoc[nodeId]);
42127 end = projection.invert(geoVecAdd(start, delta));
42129 end = cache.startLoc[nodeId];
42132 orig = orig.move(end);
42133 var angle = Math.abs(geoAngle(orig, prev, projection) - geoAngle(orig, next, projection)) * 180 / Math.PI; // Don't add orig vertex if it would just make a straight line..
42135 if (angle > 175 && angle < 185) return graph; // moving forward or backward along way?
42137 var p1 = [prev.loc, orig.loc, moved.loc, next.loc].map(projection);
42138 var p2 = [prev.loc, moved.loc, orig.loc, next.loc].map(projection);
42139 var d1 = geoPathLength(p1);
42140 var d2 = geoPathLength(p2);
42141 var insertAt = d1 <= d2 ? movedIndex : nextIndex; // moving around closed loop?
42143 if (way.isClosed() && insertAt === 0) insertAt = len;
42144 way = way.addNode(orig.id, insertAt);
42145 return graph.replace(orig).replace(way);
42146 } // Remove duplicate vertex that might have been added by
42147 // replaceMovedVertex. This is done after the unzorro checks.
42150 function removeDuplicateVertices(wayId, graph) {
42151 var way = graph.entity(wayId);
42152 var epsilon = 1e-6;
42155 function isInteresting(node, graph) {
42156 return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
42159 for (var i = 0; i < way.nodes.length; i++) {
42160 curr = graph.entity(way.nodes[i]);
42162 if (prev && curr && geoVecEqual(prev.loc, curr.loc, epsilon)) {
42163 if (!isInteresting(prev, graph)) {
42164 way = way.removeNode(prev.id);
42165 graph = graph.replace(way).remove(prev);
42166 } else if (!isInteresting(curr, graph)) {
42167 way = way.removeNode(curr.id);
42168 graph = graph.replace(way).remove(curr);
42176 } // Reorder nodes around intersections that have moved..
42178 // Start: way1.nodes: b,e (moving)
42179 // a - b - c ----- d way2.nodes: a,b,c,d (static)
42181 // e isEP1: true, isEP2, false
42183 // way1 `b,e` moved here:
42184 // a ----- c = b - d
42188 // reorder nodes way1.nodes: b,e
42189 // a ----- c - b - d way2.nodes: a,c,b,d
42195 function unZorroIntersection(intersection, graph) {
42196 var vertex = graph.entity(intersection.nodeId);
42197 var way1 = graph.entity(intersection.movedId);
42198 var way2 = graph.entity(intersection.unmovedId);
42199 var isEP1 = intersection.movedIsEP;
42200 var isEP2 = intersection.unmovedIsEP; // don't move the vertex if it is the endpoint of both ways.
42202 if (isEP1 && isEP2) return graph;
42203 var nodes1 = graph.childNodes(way1).filter(function (n) {
42204 return n !== vertex;
42206 var nodes2 = graph.childNodes(way2).filter(function (n) {
42207 return n !== vertex;
42209 if (way1.isClosed() && way1.first() === vertex.id) nodes1.push(nodes1[0]);
42210 if (way2.isClosed() && way2.first() === vertex.id) nodes2.push(nodes2[0]);
42211 var edge1 = !isEP1 && geoChooseEdge(nodes1, projection(vertex.loc), projection);
42212 var edge2 = !isEP2 && geoChooseEdge(nodes2, projection(vertex.loc), projection);
42213 var loc; // snap vertex to nearest edge (or some point between them)..
42215 if (!isEP1 && !isEP2) {
42216 var epsilon = 1e-6,
42219 for (var i = 0; i < maxIter; i++) {
42220 loc = geoVecInterp(edge1.loc, edge2.loc, 0.5);
42221 edge1 = geoChooseEdge(nodes1, projection(loc), projection);
42222 edge2 = geoChooseEdge(nodes2, projection(loc), projection);
42223 if (Math.abs(edge1.distance - edge2.distance) < epsilon) break;
42225 } else if (!isEP1) {
42231 graph = graph.replace(vertex.move(loc)); // if zorro happened, reorder nodes..
42233 if (!isEP1 && edge1.index !== way1.nodes.indexOf(vertex.id)) {
42234 way1 = way1.removeNode(vertex.id).addNode(vertex.id, edge1.index);
42235 graph = graph.replace(way1);
42238 if (!isEP2 && edge2.index !== way2.nodes.indexOf(vertex.id)) {
42239 way2 = way2.removeNode(vertex.id).addNode(vertex.id, edge2.index);
42240 graph = graph.replace(way2);
42246 function cleanupIntersections(graph) {
42247 for (var i = 0; i < cache.intersections.length; i++) {
42248 var obj = cache.intersections[i];
42249 graph = replaceMovedVertex(obj.nodeId, obj.movedId, graph, _delta);
42250 graph = replaceMovedVertex(obj.nodeId, obj.unmovedId, graph, null);
42251 graph = unZorroIntersection(obj, graph);
42252 graph = removeDuplicateVertices(obj.movedId, graph);
42253 graph = removeDuplicateVertices(obj.unmovedId, graph);
42257 } // check if moving way endpoint can cross an unmoved way, if so limit delta..
42260 function limitDelta(graph) {
42261 function moveNode(loc) {
42262 return geoVecAdd(projection(loc), _delta);
42265 for (var i = 0; i < cache.intersections.length; i++) {
42266 var obj = cache.intersections[i]; // Don't limit movement if this is vertex joins 2 endpoints..
42268 if (obj.movedIsEP && obj.unmovedIsEP) continue; // Don't limit movement if this vertex is not an endpoint anyway..
42270 if (!obj.movedIsEP) continue;
42271 var node = graph.entity(obj.nodeId);
42272 var start = projection(node.loc);
42273 var end = geoVecAdd(start, _delta);
42274 var movedNodes = graph.childNodes(graph.entity(obj.movedId));
42275 var movedPath = movedNodes.map(function (n) {
42276 return moveNode(n.loc);
42278 var unmovedNodes = graph.childNodes(graph.entity(obj.unmovedId));
42279 var unmovedPath = unmovedNodes.map(function (n) {
42280 return projection(n.loc);
42282 var hits = geoPathIntersections(movedPath, unmovedPath);
42284 for (var j = 0; i < hits.length; i++) {
42285 if (geoVecEqual(hits[j], end)) continue;
42286 var edge = geoChooseEdge(unmovedNodes, end, projection);
42287 _delta = geoVecSubtract(projection(edge.loc), start);
42292 var action = function action(graph) {
42293 if (_delta[0] === 0 && _delta[1] === 0) return graph;
42296 if (cache.intersections.length) {
42300 for (var i = 0; i < cache.nodes.length; i++) {
42301 var node = graph.entity(cache.nodes[i]);
42302 var start = projection(node.loc);
42303 var end = geoVecAdd(start, _delta);
42304 graph = graph.replace(node.move(projection.invert(end)));
42307 if (cache.intersections.length) {
42308 graph = cleanupIntersections(graph);
42314 action.delta = function () {
42321 function actionMoveMember(relationId, fromIndex, toIndex) {
42322 return function (graph) {
42323 return graph.replace(graph.entity(relationId).moveMember(fromIndex, toIndex));
42327 function actionMoveNode(nodeID, toLoc) {
42328 var action = function action(graph, t) {
42329 if (t === null || !isFinite(t)) t = 1;
42330 t = Math.min(Math.max(+t, 0), 1);
42331 var node = graph.entity(nodeID);
42332 return graph.replace(node.move(geoVecInterp(node.loc, toLoc, t)));
42335 action.transitionable = true;
42339 function actionNoop() {
42340 return function (graph) {
42345 function actionOrthogonalize(wayID, projection, vertexID, degThresh, ep) {
42346 var epsilon = ep || 1e-4;
42347 var threshold = degThresh || 13; // degrees within right or straight to alter
42348 // We test normalized dot products so we can compare as cos(angle)
42350 var lowerThreshold = Math.cos((90 - threshold) * Math.PI / 180);
42351 var upperThreshold = Math.cos(threshold * Math.PI / 180);
42353 var action = function action(graph, t) {
42354 if (t === null || !isFinite(t)) t = 1;
42355 t = Math.min(Math.max(+t, 0), 1);
42356 var way = graph.entity(wayID);
42357 way = way.removeNode(''); // sanity check - remove any consecutive duplicates
42359 if (way.tags.nonsquare) {
42360 var tags = Object.assign({}, way.tags); // since we're squaring, remove indication that this is physically unsquare
42362 delete tags.nonsquare;
42368 graph = graph.replace(way);
42369 var isClosed = way.isClosed();
42370 var nodes = graph.childNodes(way).slice(); // shallow copy
42372 if (isClosed) nodes.pop();
42374 if (vertexID !== undefined) {
42375 nodes = nodeSubset(nodes, vertexID, isClosed);
42376 if (nodes.length !== 3) return graph;
42377 } // note: all geometry functions here use the unclosed node/point/coord list
42380 var nodeCount = {};
42386 var node, point, loc, score, motions, i, j;
42388 for (i = 0; i < nodes.length; i++) {
42390 nodeCount[node.id] = (nodeCount[node.id] || 0) + 1;
42393 coord: projection(node.loc)
42397 if (points.length === 3) {
42398 // move only one vertex for right triangle
42399 for (i = 0; i < 1000; i++) {
42400 motions = points.map(calcMotion);
42401 points[corner.i].coord = geoVecAdd(points[corner.i].coord, motions[corner.i]);
42402 score = corner.dotp;
42404 if (score < epsilon) {
42409 node = graph.entity(nodes[corner.i].id);
42410 loc = projection.invert(points[corner.i].coord);
42411 graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42413 var straights = [];
42414 var simplified = []; // Remove points from nearly straight sections..
42415 // This produces a simplified shape to orthogonalize
42417 for (i = 0; i < points.length; i++) {
42421 if (isClosed || i > 0 && i < points.length - 1) {
42422 var a = points[(i - 1 + points.length) % points.length];
42423 var b = points[(i + 1) % points.length];
42424 dotp = Math.abs(geoOrthoNormalizedDotProduct(a.coord, b.coord, point.coord));
42427 if (dotp > upperThreshold) {
42428 straights.push(point);
42430 simplified.push(point);
42432 } // Orthogonalize the simplified shape
42435 var bestPoints = clonePoints(simplified);
42436 var originalPoints = clonePoints(simplified);
42439 for (i = 0; i < 1000; i++) {
42440 motions = simplified.map(calcMotion);
42442 for (j = 0; j < motions.length; j++) {
42443 simplified[j].coord = geoVecAdd(simplified[j].coord, motions[j]);
42446 var newScore = geoOrthoCalcScore(simplified, isClosed, epsilon, threshold);
42448 if (newScore < score) {
42449 bestPoints = clonePoints(simplified);
42453 if (score < epsilon) {
42458 var bestCoords = bestPoints.map(function (p) {
42461 if (isClosed) bestCoords.push(bestCoords[0]); // move the nodes that should move
42463 for (i = 0; i < bestPoints.length; i++) {
42464 point = bestPoints[i];
42466 if (!geoVecEqual(originalPoints[i].coord, point.coord)) {
42467 node = graph.entity(point.id);
42468 loc = projection.invert(point.coord);
42469 graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42471 } // move the nodes along straight segments
42474 for (i = 0; i < straights.length; i++) {
42475 point = straights[i];
42476 if (nodeCount[point.id] > 1) continue; // skip self-intersections
42478 node = graph.entity(point.id);
42480 if (t === 1 && graph.parentWays(node).length === 1 && graph.parentRelations(node).length === 0 && !node.hasInterestingTags()) {
42481 // remove uninteresting points..
42482 graph = actionDeleteNode(node.id)(graph);
42484 // move interesting points to the nearest edge..
42485 var choice = geoVecProject(point.coord, bestCoords);
42488 loc = projection.invert(choice.target);
42489 graph = graph.replace(node.move(geoVecInterp(node.loc, loc, t)));
42497 function clonePoints(array) {
42498 return array.map(function (p) {
42501 coord: [p.coord[0], p.coord[1]]
42506 function calcMotion(point, i, array) {
42507 // don't try to move the endpoints of a non-closed way.
42508 if (!isClosed && (i === 0 || i === array.length - 1)) return [0, 0]; // don't try to move a node that appears more than once (self intersection)
42510 if (nodeCount[array[i].id] > 1) return [0, 0];
42511 var a = array[(i - 1 + array.length) % array.length].coord;
42512 var origin = point.coord;
42513 var b = array[(i + 1) % array.length].coord;
42514 var p = geoVecSubtract(a, origin);
42515 var q = geoVecSubtract(b, origin);
42516 var scale = 2 * Math.min(geoVecLength(p), geoVecLength(q));
42517 p = geoVecNormalize(p);
42518 q = geoVecNormalize(q);
42519 var dotp = p[0] * q[0] + p[1] * q[1];
42520 var val = Math.abs(dotp);
42522 if (val < lowerThreshold) {
42523 // nearly orthogonal
42526 var vec = geoVecNormalize(geoVecAdd(p, q));
42527 return geoVecScale(vec, 0.1 * dotp * scale);
42530 return [0, 0]; // do nothing
42532 }; // if we are only orthogonalizing one vertex,
42533 // get that vertex and the previous and next
42536 function nodeSubset(nodes, vertexID, isClosed) {
42537 var first = isClosed ? 0 : 1;
42538 var last = isClosed ? nodes.length : nodes.length - 1;
42540 for (var i = first; i < last; i++) {
42541 if (nodes[i].id === vertexID) {
42542 return [nodes[(i - 1 + nodes.length) % nodes.length], nodes[i], nodes[(i + 1) % nodes.length]];
42549 action.disabled = function (graph) {
42550 var way = graph.entity(wayID);
42551 way = way.removeNode(''); // sanity check - remove any consecutive duplicates
42553 graph = graph.replace(way);
42554 var isClosed = way.isClosed();
42555 var nodes = graph.childNodes(way).slice(); // shallow copy
42557 if (isClosed) nodes.pop();
42558 var allowStraightAngles = false;
42560 if (vertexID !== undefined) {
42561 allowStraightAngles = true;
42562 nodes = nodeSubset(nodes, vertexID, isClosed);
42563 if (nodes.length !== 3) return 'end_vertex';
42566 var coords = nodes.map(function (n) {
42567 return projection(n.loc);
42569 var score = geoOrthoCanOrthogonalize(coords, isClosed, epsilon, threshold, allowStraightAngles);
42571 if (score === null) {
42572 return 'not_squarish';
42573 } else if (score === 0) {
42574 return 'square_enough';
42580 action.transitionable = true;
42585 // `turn` must be an `osmTurn` object
42586 // see osm/intersection.js, pathToTurn()
42588 // This specifies a restriction of type `restriction` when traveling from
42589 // `turn.from.way` toward `turn.to.way` via `turn.via.node` OR `turn.via.ways`.
42590 // (The action does not check that these entities form a valid intersection.)
42592 // From, to, and via ways should be split before calling this action.
42593 // (old versions of the code would split the ways here, but we no longer do it)
42595 // For testing convenience, accepts a restrictionID to assign to the new
42596 // relation. Normally, this will be undefined and the relation will
42597 // automatically be assigned a new ID.
42600 function actionRestrictTurn(turn, restrictionType, restrictionID) {
42601 return function (graph) {
42602 var fromWay = graph.entity(turn.from.way);
42603 var toWay = graph.entity(turn.to.way);
42604 var viaNode = turn.via.node && graph.entity(turn.via.node);
42605 var viaWays = turn.via.ways && turn.via.ways.map(function (id) {
42606 return graph.entity(id);
42621 } else if (viaWays) {
42622 viaWays.forEach(function (viaWay) {
42636 return graph.replace(osmRelation({
42639 type: 'restriction',
42640 restriction: restrictionType
42647 function actionRevert(id) {
42648 var action = function action(graph) {
42649 var entity = graph.hasEntity(id),
42650 base = graph.base().entities[id];
42652 if (entity && !base) {
42653 // entity will be removed..
42654 if (entity.type === 'node') {
42655 graph.parentWays(entity).forEach(function (parent) {
42656 parent = parent.removeNode(id);
42657 graph = graph.replace(parent);
42659 if (parent.isDegenerate()) {
42660 graph = actionDeleteWay(parent.id)(graph);
42665 graph.parentRelations(entity).forEach(function (parent) {
42666 parent = parent.removeMembersWithID(id);
42667 graph = graph.replace(parent);
42669 if (parent.isDegenerate()) {
42670 graph = actionDeleteRelation(parent.id)(graph);
42675 return graph.revert(id);
42681 function actionRotate(rotateIds, pivot, angle, projection) {
42682 var action = function action(graph) {
42683 return graph.update(function (graph) {
42684 utilGetAllNodes(rotateIds, graph).forEach(function (node) {
42685 var point = geoRotate([projection(node.loc)], angle, pivot)[0];
42686 graph = graph.replace(node.move(projection.invert(point)));
42694 function actionScale(ids, pivotLoc, scaleFactor, projection) {
42695 return function (graph) {
42696 return graph.update(function (graph) {
42698 utilGetAllNodes(ids, graph).forEach(function (node) {
42699 point = projection(node.loc);
42700 radial = [point[0] - pivotLoc[0], point[1] - pivotLoc[1]];
42701 point = [pivotLoc[0] + scaleFactor * radial[0], pivotLoc[1] + scaleFactor * radial[1]];
42702 graph = graph.replace(node.move(projection.invert(point)));
42708 /* Align nodes along their common axis */
42710 function actionStraightenNodes(nodeIDs, projection) {
42711 function positionAlongWay(a, o, b) {
42712 return geoVecDot(a, b, o) / geoVecDot(b, b, o);
42713 } // returns the endpoints of the long axis of symmetry of the `points` bounding rect
42716 function getEndpoints(points) {
42717 var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
42718 // The shape's surrounding rectangle has 2 axes of symmetry.
42719 // Snap points to the long axis
42721 var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
42722 var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
42723 var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
42724 var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
42725 var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
42734 var action = function action(graph, t) {
42735 if (t === null || !isFinite(t)) t = 1;
42736 t = Math.min(Math.max(+t, 0), 1);
42737 var nodes = nodeIDs.map(function (id) {
42738 return graph.entity(id);
42740 var points = nodes.map(function (n) {
42741 return projection(n.loc);
42743 var endpoints = getEndpoints(points);
42744 var startPoint = endpoints[0];
42745 var endPoint = endpoints[1]; // Move points onto the line connecting the endpoints
42747 for (var i = 0; i < points.length; i++) {
42748 var node = nodes[i];
42749 var point = points[i];
42750 var u = positionAlongWay(point, startPoint, endPoint);
42751 var point2 = geoVecInterp(startPoint, endPoint, u);
42752 var loc2 = projection.invert(point2);
42753 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
42759 action.disabled = function (graph) {
42760 var nodes = nodeIDs.map(function (id) {
42761 return graph.entity(id);
42763 var points = nodes.map(function (n) {
42764 return projection(n.loc);
42766 var endpoints = getEndpoints(points);
42767 var startPoint = endpoints[0];
42768 var endPoint = endpoints[1];
42769 var maxDistance = 0;
42771 for (var i = 0; i < points.length; i++) {
42772 var point = points[i];
42773 var u = positionAlongWay(point, startPoint, endPoint);
42774 var p = geoVecInterp(startPoint, endPoint, u);
42775 var dist = geoVecLength(p, point);
42777 if (!isNaN(dist) && dist > maxDistance) {
42778 maxDistance = dist;
42782 if (maxDistance < 0.0001) {
42783 return 'straight_enough';
42787 action.transitionable = true;
42792 * Based on https://github.com/openstreetmap/potlatch2/net/systemeD/potlatch2/tools/Straighten.as
42795 function actionStraightenWay(selectedIDs, projection) {
42796 function positionAlongWay(a, o, b) {
42797 return geoVecDot(a, b, o) / geoVecDot(b, b, o);
42798 } // Return all selected ways as a continuous, ordered array of nodes
42801 function allNodes(graph) {
42803 var startNodes = [];
42805 var remainingWays = [];
42806 var selectedWays = selectedIDs.filter(function (w) {
42807 return graph.entity(w).type === 'way';
42809 var selectedNodes = selectedIDs.filter(function (n) {
42810 return graph.entity(n).type === 'node';
42813 for (var i = 0; i < selectedWays.length; i++) {
42814 var way = graph.entity(selectedWays[i]);
42815 nodes = way.nodes.slice(0);
42816 remainingWays.push(nodes);
42817 startNodes.push(nodes[0]);
42818 endNodes.push(nodes[nodes.length - 1]);
42819 } // Remove duplicate end/startNodes (duplicate nodes cannot be at the line end,
42820 // and need to be removed so currNode difference calculation below works)
42821 // i.e. ["n-1", "n-1", "n-2"] => ["n-2"]
42824 startNodes = startNodes.filter(function (n) {
42825 return startNodes.indexOf(n) === startNodes.lastIndexOf(n);
42827 endNodes = endNodes.filter(function (n) {
42828 return endNodes.indexOf(n) === endNodes.lastIndexOf(n);
42829 }); // Choose the initial endpoint to start from
42831 var currNode = utilArrayDifference(startNodes, endNodes).concat(utilArrayDifference(endNodes, startNodes))[0];
42833 nodes = []; // Create nested function outside of loop to avoid "function in loop" lint error
42835 var getNextWay = function getNextWay(currNode, remainingWays) {
42836 return remainingWays.filter(function (way) {
42837 return way[0] === currNode || way[way.length - 1] === currNode;
42839 }; // Add nodes to end of nodes array, until all ways are added
42842 while (remainingWays.length) {
42843 nextWay = getNextWay(currNode, remainingWays);
42844 remainingWays = utilArrayDifference(remainingWays, [nextWay]);
42846 if (nextWay[0] !== currNode) {
42850 nodes = nodes.concat(nextWay);
42851 currNode = nodes[nodes.length - 1];
42852 } // If user selected 2 nodes to straighten between, then slice nodes array to those nodes
42855 if (selectedNodes.length === 2) {
42856 var startNodeIdx = nodes.indexOf(selectedNodes[0]);
42857 var endNodeIdx = nodes.indexOf(selectedNodes[1]);
42858 var sortedStartEnd = [startNodeIdx, endNodeIdx];
42859 sortedStartEnd.sort(function (a, b) {
42862 nodes = nodes.slice(sortedStartEnd[0], sortedStartEnd[1] + 1);
42865 return nodes.map(function (n) {
42866 return graph.entity(n);
42870 function shouldKeepNode(node, graph) {
42871 return graph.parentWays(node).length > 1 || graph.parentRelations(node).length || node.hasInterestingTags();
42874 var action = function action(graph, t) {
42875 if (t === null || !isFinite(t)) t = 1;
42876 t = Math.min(Math.max(+t, 0), 1);
42877 var nodes = allNodes(graph);
42878 var points = nodes.map(function (n) {
42879 return projection(n.loc);
42881 var startPoint = points[0];
42882 var endPoint = points[points.length - 1];
42886 for (i = 1; i < points.length - 1; i++) {
42887 var node = nodes[i];
42888 var point = points[i];
42890 if (t < 1 || shouldKeepNode(node, graph)) {
42891 var u = positionAlongWay(point, startPoint, endPoint);
42892 var p = geoVecInterp(startPoint, endPoint, u);
42893 var loc2 = projection.invert(p);
42894 graph = graph.replace(node.move(geoVecInterp(node.loc, loc2, t)));
42897 if (toDelete.indexOf(node) === -1) {
42898 toDelete.push(node);
42903 for (i = 0; i < toDelete.length; i++) {
42904 graph = actionDeleteNode(toDelete[i].id)(graph);
42910 action.disabled = function (graph) {
42911 // check way isn't too bendy
42912 var nodes = allNodes(graph);
42913 var points = nodes.map(function (n) {
42914 return projection(n.loc);
42916 var startPoint = points[0];
42917 var endPoint = points[points.length - 1];
42918 var threshold = 0.2 * geoVecLength(startPoint, endPoint);
42921 if (threshold === 0) {
42922 return 'too_bendy';
42925 var maxDistance = 0;
42927 for (i = 1; i < points.length - 1; i++) {
42928 var point = points[i];
42929 var u = positionAlongWay(point, startPoint, endPoint);
42930 var p = geoVecInterp(startPoint, endPoint, u);
42931 var dist = geoVecLength(p, point); // to bendy if point is off by 20% of total start/end distance in projected space
42933 if (isNaN(dist) || dist > threshold) {
42934 return 'too_bendy';
42935 } else if (dist > maxDistance) {
42936 maxDistance = dist;
42940 var keepingAllNodes = nodes.every(function (node, i) {
42941 return i === 0 || i === nodes.length - 1 || shouldKeepNode(node, graph);
42944 if (maxDistance < 0.0001 && // Allow straightening even if already straight in order to remove extraneous nodes
42946 return 'straight_enough';
42950 action.transitionable = true;
42955 // `turn` must be an `osmTurn` object with a `restrictionID` property.
42956 // see osm/intersection.js, pathToTurn()
42959 function actionUnrestrictTurn(turn) {
42960 return function (graph) {
42961 return actionDeleteRelation(turn.restrictionID)(graph);
42965 /* Reflect the given area around its axis of symmetry */
42967 function actionReflect(reflectIds, projection) {
42968 var _useLongAxis = true;
42970 var action = function action(graph, t) {
42971 if (t === null || !isFinite(t)) t = 1;
42972 t = Math.min(Math.max(+t, 0), 1);
42973 var nodes = utilGetAllNodes(reflectIds, graph);
42974 var points = nodes.map(function (n) {
42975 return projection(n.loc);
42977 var ssr = geoGetSmallestSurroundingRectangle(points); // Choose line pq = axis of symmetry.
42978 // The shape's surrounding rectangle has 2 axes of symmetry.
42979 // Reflect across the longer axis by default.
42981 var p1 = [(ssr.poly[0][0] + ssr.poly[1][0]) / 2, (ssr.poly[0][1] + ssr.poly[1][1]) / 2];
42982 var q1 = [(ssr.poly[2][0] + ssr.poly[3][0]) / 2, (ssr.poly[2][1] + ssr.poly[3][1]) / 2];
42983 var p2 = [(ssr.poly[3][0] + ssr.poly[4][0]) / 2, (ssr.poly[3][1] + ssr.poly[4][1]) / 2];
42984 var q2 = [(ssr.poly[1][0] + ssr.poly[2][0]) / 2, (ssr.poly[1][1] + ssr.poly[2][1]) / 2];
42986 var isLong = geoVecLength(p1, q1) > geoVecLength(p2, q2);
42988 if (_useLongAxis && isLong || !_useLongAxis && !isLong) {
42994 } // reflect c across pq
42995 // http://math.stackexchange.com/questions/65503/point-reflection-over-a-line
42998 var dx = q[0] - p[0];
42999 var dy = q[1] - p[1];
43000 var a = (dx * dx - dy * dy) / (dx * dx + dy * dy);
43001 var b = 2 * dx * dy / (dx * dx + dy * dy);
43003 for (var i = 0; i < nodes.length; i++) {
43004 var node = nodes[i];
43005 var c = projection(node.loc);
43006 var c2 = [a * (c[0] - p[0]) + b * (c[1] - p[1]) + p[0], b * (c[0] - p[0]) - a * (c[1] - p[1]) + p[1]];
43007 var loc2 = projection.invert(c2);
43008 node = node.move(geoVecInterp(node.loc, loc2, t));
43009 graph = graph.replace(node);
43015 action.useLongAxis = function (val) {
43016 if (!arguments.length) return _useLongAxis;
43017 _useLongAxis = val;
43021 action.transitionable = true;
43025 function actionUpgradeTags(entityId, oldTags, replaceTags) {
43026 return function (graph) {
43027 var entity = graph.entity(entityId);
43028 var tags = Object.assign({}, entity.tags); // shallow copy
43033 for (var oldTagKey in oldTags) {
43034 if (!(oldTagKey in tags)) continue; // wildcard match
43036 if (oldTags[oldTagKey] === '*') {
43037 // note the value since we might need to transfer it
43038 transferValue = tags[oldTagKey];
43039 delete tags[oldTagKey]; // exact match
43040 } else if (oldTags[oldTagKey] === tags[oldTagKey]) {
43041 delete tags[oldTagKey]; // match is within semicolon-delimited values
43043 var vals = tags[oldTagKey].split(';').filter(Boolean);
43044 var oldIndex = vals.indexOf(oldTags[oldTagKey]);
43046 if (vals.length === 1 || oldIndex === -1) {
43047 delete tags[oldTagKey];
43049 if (replaceTags && replaceTags[oldTagKey]) {
43050 // replacing a value within a semicolon-delimited value, note the index
43051 semiIndex = oldIndex;
43054 vals.splice(oldIndex, 1);
43055 tags[oldTagKey] = vals.join(';');
43061 for (var replaceKey in replaceTags) {
43062 var replaceValue = replaceTags[replaceKey];
43064 if (replaceValue === '*') {
43065 if (tags[replaceKey] && tags[replaceKey] !== 'no') {
43066 // allow any pre-existing value except `no` (troll tag)
43069 // otherwise assume `yes` is okay
43070 tags[replaceKey] = 'yes';
43072 } else if (replaceValue === '$1') {
43073 tags[replaceKey] = transferValue;
43075 if (tags[replaceKey] && oldTags[replaceKey] && semiIndex !== undefined) {
43076 // don't override preexisting values
43077 var existingVals = tags[replaceKey].split(';').filter(Boolean);
43079 if (existingVals.indexOf(replaceValue) === -1) {
43080 existingVals.splice(semiIndex, 0, replaceValue);
43081 tags[replaceKey] = existingVals.join(';');
43084 tags[replaceKey] = replaceValue;
43090 return graph.replace(entity.update({
43096 function behaviorEdit(context) {
43097 function behavior() {
43098 context.map().minzoom(context.minEditableZoom());
43101 behavior.off = function () {
43102 context.map().minzoom(0);
43109 The hover behavior adds the `.hover` class on pointerover to all elements to which
43110 the identical datum is bound, and removes it on pointerout.
43112 The :hover pseudo-class is insufficient for iD's purposes because a datum's visual
43113 representation may consist of several elements scattered throughout the DOM hierarchy.
43114 Only one of these elements can have the :hover pseudo-class, but all of them will
43115 have the .hover class.
43118 function behaviorHover(context) {
43119 var dispatch = dispatch$8('hover');
43121 var _selection = select(null);
43123 var _newNodeId = null;
43124 var _initialNodeID = null;
43130 var _targets = []; // use pointer events on supported platforms; fallback to mouse events
43132 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
43134 function keydown(d3_event) {
43135 if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
43136 _selection.selectAll('.hover').classed('hover-suppressed', true).classed('hover', false);
43138 _selection.classed('hover-disabled', true);
43140 dispatch.call('hover', this, null);
43144 function keyup(d3_event) {
43145 if (_altDisables && d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
43146 _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false).classed('hover', true);
43148 _selection.classed('hover-disabled', false);
43150 dispatch.call('hover', this, _targets);
43154 function behavior(selection) {
43155 _selection = selection;
43158 if (_initialNodeID) {
43159 _newNodeId = _initialNodeID;
43160 _initialNodeID = null;
43165 _selection.on(_pointerPrefix + 'over.hover', pointerover).on(_pointerPrefix + 'out.hover', pointerout) // treat pointerdown as pointerover for touch devices
43166 .on(_pointerPrefix + 'down.hover', pointerover);
43168 select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', pointerout, true).on('keydown.hover', keydown).on('keyup.hover', keyup);
43170 function eventTarget(d3_event) {
43171 var datum = d3_event.target && d3_event.target.__data__;
43172 if (_typeof(datum) !== 'object') return null;
43174 if (!(datum instanceof osmEntity) && datum.properties && datum.properties.entity instanceof osmEntity) {
43175 return datum.properties.entity;
43181 function pointerover(d3_event) {
43182 // ignore mouse hovers with buttons pressed unless dragging
43183 if (context.mode().id.indexOf('drag') === -1 && (!d3_event.pointerType || d3_event.pointerType === 'mouse') && d3_event.buttons) return;
43184 var target = eventTarget(d3_event);
43186 if (target && _targets.indexOf(target) === -1) {
43187 _targets.push(target);
43189 updateHover(d3_event, _targets);
43193 function pointerout(d3_event) {
43194 var target = eventTarget(d3_event);
43196 var index = _targets.indexOf(target);
43198 if (index !== -1) {
43199 _targets.splice(index);
43201 updateHover(d3_event, _targets);
43205 function allowsVertex(d) {
43206 return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
43209 function modeAllowsHover(target) {
43210 var mode = context.mode();
43212 if (mode.id === 'add-point') {
43213 return mode.preset.matchGeometry('vertex') || target.type !== 'way' && target.geometry(context.graph()) !== 'vertex';
43219 function updateHover(d3_event, targets) {
43220 _selection.selectAll('.hover').classed('hover', false);
43222 _selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
43224 var mode = context.mode();
43226 if (!_newNodeId && (mode.id === 'draw-line' || mode.id === 'draw-area')) {
43227 var node = targets.find(function (target) {
43228 return target instanceof osmEntity && target.type === 'node';
43230 _newNodeId = node && node.id;
43233 targets = targets.filter(function (datum) {
43234 if (datum instanceof osmEntity) {
43235 // If drawing a way, don't hover on a node that was just placed. #3974
43236 return datum.id !== _newNodeId && (datum.type !== 'node' || !_ignoreVertex || allowsVertex(datum)) && modeAllowsHover(datum);
43243 for (var i in targets) {
43244 var datum = targets[i]; // What are we hovering over?
43246 if (datum.__featurehash__) {
43247 // hovering custom data
43248 selector += ', .data' + datum.__featurehash__;
43249 } else if (datum instanceof QAItem) {
43250 selector += ', .' + datum.service + '.itemId-' + datum.id;
43251 } else if (datum instanceof osmNote) {
43252 selector += ', .note-' + datum.id;
43253 } else if (datum instanceof osmEntity) {
43254 selector += ', .' + datum.id;
43256 if (datum.type === 'relation') {
43257 for (var j in datum.members) {
43258 selector += ', .' + datum.members[j].id;
43264 var suppressed = _altDisables && d3_event && d3_event.altKey;
43266 if (selector.trim().length) {
43267 // remove the first comma
43268 selector = selector.slice(1);
43270 _selection.selectAll(selector).classed(suppressed ? 'hover-suppressed' : 'hover', true);
43273 dispatch.call('hover', this, !suppressed && targets);
43277 behavior.off = function (selection) {
43278 selection.selectAll('.hover').classed('hover', false);
43279 selection.selectAll('.hover-suppressed').classed('hover-suppressed', false);
43280 selection.classed('hover-disabled', false);
43281 selection.on(_pointerPrefix + 'over.hover', null).on(_pointerPrefix + 'out.hover', null).on(_pointerPrefix + 'down.hover', null);
43282 select(window).on(_pointerPrefix + 'up.hover pointercancel.hover', null, true).on('keydown.hover', null).on('keyup.hover', null);
43285 behavior.altDisables = function (val) {
43286 if (!arguments.length) return _altDisables;
43287 _altDisables = val;
43291 behavior.ignoreVertex = function (val) {
43292 if (!arguments.length) return _ignoreVertex;
43293 _ignoreVertex = val;
43297 behavior.initialNodeID = function (nodeId) {
43298 _initialNodeID = nodeId;
43302 return utilRebind(behavior, dispatch, 'on');
43305 var _disableSpace = false;
43306 var _lastSpace = null;
43307 function behaviorDraw(context) {
43308 var dispatch = dispatch$8('move', 'down', 'downcancel', 'click', 'clickWay', 'clickNode', 'undo', 'cancel', 'finish');
43309 var keybinding = utilKeybinding('draw');
43311 var _hover = behaviorHover(context).altDisables(true).ignoreVertex(true).on('hover', context.ui().sidebar.hover);
43313 var _edit = behaviorEdit(context);
43315 var _closeTolerance = 4;
43316 var _tolerance = 12;
43317 var _mouseLeave = false;
43318 var _lastMouse = null;
43320 var _lastPointerUpEvent;
43322 var _downPointer; // use pointer events on supported platforms; fallback to mouse events
43325 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // related code
43326 // - `mode/drag_node.js` `datum()`
43329 function datum(d3_event) {
43330 var mode = context.mode();
43331 var isNote = mode && mode.id.indexOf('note') !== -1;
43332 if (d3_event.altKey || isNote) return {};
43335 if (d3_event.type === 'keydown') {
43336 element = _lastMouse && _lastMouse.target;
43338 element = d3_event.target;
43339 } // When drawing, snap only to touch targets..
43340 // (this excludes area fills and active drawing elements)
43343 var d = element.__data__;
43344 return d && d.properties && d.properties.target ? d : {};
43347 function pointerdown(d3_event) {
43348 if (_downPointer) return;
43349 var pointerLocGetter = utilFastMouse(this);
43351 id: d3_event.pointerId || 'mouse',
43352 pointerLocGetter: pointerLocGetter,
43353 downTime: +new Date(),
43354 downLoc: pointerLocGetter(d3_event)
43356 dispatch.call('down', this, d3_event, datum(d3_event));
43359 function pointerup(d3_event) {
43360 if (!_downPointer || _downPointer.id !== (d3_event.pointerId || 'mouse')) return;
43361 var downPointer = _downPointer;
43362 _downPointer = null;
43363 _lastPointerUpEvent = d3_event;
43364 if (downPointer.isCancelled) return;
43365 var t2 = +new Date();
43366 var p2 = downPointer.pointerLocGetter(d3_event);
43367 var dist = geoVecLength(downPointer.downLoc, p2);
43369 if (dist < _closeTolerance || dist < _tolerance && t2 - downPointer.downTime < 500) {
43370 // Prevent a quick second click
43371 select(window).on('click.draw-block', function () {
43372 d3_event.stopPropagation();
43374 context.map().dblclickZoomEnable(false);
43375 window.setTimeout(function () {
43376 context.map().dblclickZoomEnable(true);
43377 select(window).on('click.draw-block', null);
43379 click(d3_event, p2);
43383 function pointermove(d3_event) {
43384 if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse') && !_downPointer.isCancelled) {
43385 var p2 = _downPointer.pointerLocGetter(d3_event);
43387 var dist = geoVecLength(_downPointer.downLoc, p2);
43389 if (dist >= _closeTolerance) {
43390 _downPointer.isCancelled = true;
43391 dispatch.call('downcancel', this);
43395 if (d3_event.pointerType && d3_event.pointerType !== 'mouse' || d3_event.buttons || _downPointer) return; // HACK: Mobile Safari likes to send one or more `mouse` type pointermove
43396 // events immediately after non-mouse pointerup events; detect and ignore them.
43398 if (_lastPointerUpEvent && _lastPointerUpEvent.pointerType !== 'mouse' && d3_event.timeStamp - _lastPointerUpEvent.timeStamp < 100) return;
43399 _lastMouse = d3_event;
43400 dispatch.call('move', this, d3_event, datum(d3_event));
43403 function pointercancel(d3_event) {
43404 if (_downPointer && _downPointer.id === (d3_event.pointerId || 'mouse')) {
43405 if (!_downPointer.isCancelled) {
43406 dispatch.call('downcancel', this);
43409 _downPointer = null;
43413 function mouseenter() {
43414 _mouseLeave = false;
43417 function mouseleave() {
43418 _mouseLeave = true;
43421 function allowsVertex(d) {
43422 return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
43424 // - `mode/drag_node.js` `doMove()`
43425 // - `behavior/draw.js` `click()`
43426 // - `behavior/draw_way.js` `move()`
43429 function click(d3_event, loc) {
43430 var d = datum(d3_event);
43431 var target = d && d.properties && d.properties.entity;
43432 var mode = context.mode();
43434 if (target && target.type === 'node' && allowsVertex(target)) {
43436 dispatch.call('clickNode', this, target, d);
43438 } else if (target && target.type === 'way' && (mode.id !== 'add-point' || mode.preset.matchGeometry('vertex'))) {
43440 var choice = geoChooseEdge(context.graph().childNodes(target), loc, context.projection, context.activeID());
43443 var edge = [target.nodes[choice.index - 1], target.nodes[choice.index]];
43444 dispatch.call('clickWay', this, choice.loc, edge, d);
43447 } else if (mode.id !== 'add-point' || mode.preset.matchGeometry('point')) {
43448 var locLatLng = context.projection.invert(loc);
43449 dispatch.call('click', this, locLatLng, d);
43451 } // treat a spacebar press like a click
43454 function space(d3_event) {
43455 d3_event.preventDefault();
43456 d3_event.stopPropagation();
43457 var currSpace = context.map().mouse();
43459 if (_disableSpace && _lastSpace) {
43460 var dist = geoVecLength(_lastSpace, currSpace);
43462 if (dist > _tolerance) {
43463 _disableSpace = false;
43467 if (_disableSpace || _mouseLeave || !_lastMouse) return; // user must move mouse or release space bar to allow another click
43469 _lastSpace = currSpace;
43470 _disableSpace = true;
43471 select(window).on('keyup.space-block', function () {
43472 d3_event.preventDefault();
43473 d3_event.stopPropagation();
43474 _disableSpace = false;
43475 select(window).on('keyup.space-block', null);
43476 }); // get the current mouse position
43478 var loc = context.map().mouse() || // or the map center if the mouse has never entered the map
43479 context.projection(context.map().center());
43480 click(d3_event, loc);
43483 function backspace(d3_event) {
43484 d3_event.preventDefault();
43485 dispatch.call('undo');
43488 function del(d3_event) {
43489 d3_event.preventDefault();
43490 dispatch.call('cancel');
43493 function ret(d3_event) {
43494 d3_event.preventDefault();
43495 dispatch.call('finish');
43498 function behavior(selection) {
43499 context.install(_hover);
43500 context.install(_edit);
43501 _downPointer = null;
43502 keybinding.on('⌫', backspace).on('⌦', del).on('⎋', ret).on('↩', ret).on('space', space).on('⌥space', space);
43503 selection.on('mouseenter.draw', mouseenter).on('mouseleave.draw', mouseleave).on(_pointerPrefix + 'down.draw', pointerdown).on(_pointerPrefix + 'move.draw', pointermove);
43504 select(window).on(_pointerPrefix + 'up.draw', pointerup, true).on('pointercancel.draw', pointercancel, true);
43505 select(document).call(keybinding);
43509 behavior.off = function (selection) {
43510 context.ui().sidebar.hover.cancel();
43511 context.uninstall(_hover);
43512 context.uninstall(_edit);
43513 selection.on('mouseenter.draw', null).on('mouseleave.draw', null).on(_pointerPrefix + 'down.draw', null).on(_pointerPrefix + 'move.draw', null);
43514 select(window).on(_pointerPrefix + 'up.draw', null).on('pointercancel.draw', null); // note: keyup.space-block, click.draw-block should remain
43516 select(document).call(keybinding.unbind);
43519 behavior.hover = function () {
43523 return utilRebind(behavior, dispatch, 'on');
43526 function initRange(domain, range) {
43527 switch (arguments.length) {
43532 this.range(domain);
43536 this.range(range).domain(domain);
43543 function constants(x) {
43544 return function () {
43549 function number(x) {
43554 function identity$1(x) {
43558 function normalize(a, b) {
43559 return (b -= a = +a) ? function (x) {
43560 return (x - a) / b;
43561 } : constants(isNaN(b) ? NaN : 0.5);
43564 function clamper(a, b) {
43566 if (a > b) t = a, a = b, b = t;
43567 return function (x) {
43568 return Math.max(a, Math.min(b, x));
43570 } // normalize(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
43571 // interpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding range value x in [a,b].
43574 function bimap(domain, range, interpolate) {
43575 var d0 = domain[0],
43579 if (d1 < d0) d0 = normalize(d1, d0), r0 = interpolate(r1, r0);else d0 = normalize(d0, d1), r0 = interpolate(r0, r1);
43580 return function (x) {
43585 function polymap(domain, range, interpolate) {
43586 var j = Math.min(domain.length, range.length) - 1,
43589 i = -1; // Reverse descending domains.
43591 if (domain[j] < domain[0]) {
43592 domain = domain.slice().reverse();
43593 range = range.slice().reverse();
43597 d[i] = normalize(domain[i], domain[i + 1]);
43598 r[i] = interpolate(range[i], range[i + 1]);
43601 return function (x) {
43602 var i = bisectRight(domain, x, 1, j) - 1;
43603 return r[i](d[i](x));
43607 function copy(source, target) {
43608 return target.domain(source.domain()).range(source.range()).interpolate(source.interpolate()).clamp(source.clamp()).unknown(source.unknown());
43610 function transformer() {
43613 interpolate = interpolate$1,
43617 clamp = identity$1,
43622 function rescale() {
43623 var n = Math.min(domain.length, range.length);
43624 if (clamp !== identity$1) clamp = clamper(domain[0], domain[n - 1]);
43625 piecewise = n > 2 ? polymap : bimap;
43626 output = input = null;
43630 function scale(x) {
43631 return x == null || isNaN(x = +x) ? unknown : (output || (output = piecewise(domain.map(transform), range, interpolate)))(transform(clamp(x)));
43634 scale.invert = function (y) {
43635 return clamp(untransform((input || (input = piecewise(range, domain.map(transform), d3_interpolateNumber)))(y)));
43638 scale.domain = function (_) {
43639 return arguments.length ? (domain = Array.from(_, number), rescale()) : domain.slice();
43642 scale.range = function (_) {
43643 return arguments.length ? (range = Array.from(_), rescale()) : range.slice();
43646 scale.rangeRound = function (_) {
43647 return range = Array.from(_), interpolate = interpolateRound, rescale();
43650 scale.clamp = function (_) {
43651 return arguments.length ? (clamp = _ ? true : identity$1, rescale()) : clamp !== identity$1;
43654 scale.interpolate = function (_) {
43655 return arguments.length ? (interpolate = _, rescale()) : interpolate;
43658 scale.unknown = function (_) {
43659 return arguments.length ? (unknown = _, scale) : unknown;
43662 return function (t, u) {
43663 transform = t, untransform = u;
43667 function continuous() {
43668 return transformer()(identity$1, identity$1);
43671 function formatDecimal (x) {
43672 return Math.abs(x = Math.round(x)) >= 1e21 ? x.toLocaleString("en").replace(/,/g, "") : x.toString(10);
43673 } // Computes the decimal coefficient and exponent of the specified number x with
43674 // significant digits p, where x is positive and p is in [1, 21] or undefined.
43675 // For example, formatDecimalParts(1.23) returns ["123", 0].
43677 function formatDecimalParts(x, p) {
43678 if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
43681 coefficient = x.slice(0, i); // The string returned by toExponential either has the form \d\.\d+e[-+]\d+
43682 // (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
43684 return [coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient, +x.slice(i + 1)];
43687 function exponent (x) {
43688 return x = formatDecimalParts(Math.abs(x)), x ? x[1] : NaN;
43691 function formatGroup (grouping, thousands) {
43692 return function (value, width) {
43693 var i = value.length,
43699 while (i > 0 && g > 0) {
43700 if (length + g + 1 > width) g = Math.max(1, width - length);
43701 t.push(value.substring(i -= g, i + g));
43702 if ((length += g + 1) > width) break;
43703 g = grouping[j = (j + 1) % grouping.length];
43706 return t.reverse().join(thousands);
43710 function formatNumerals (numerals) {
43711 return function (value) {
43712 return value.replace(/[0-9]/g, function (i) {
43713 return numerals[+i];
43718 // [[fill]align][sign][symbol][0][width][,][.precision][~][type]
43719 var re = /^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;
43720 function formatSpecifier(specifier) {
43721 if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
43723 return new FormatSpecifier({
43731 precision: match[8] && match[8].slice(1),
43736 formatSpecifier.prototype = FormatSpecifier.prototype; // instanceof
43738 function FormatSpecifier(specifier) {
43739 this.fill = specifier.fill === undefined ? " " : specifier.fill + "";
43740 this.align = specifier.align === undefined ? ">" : specifier.align + "";
43741 this.sign = specifier.sign === undefined ? "-" : specifier.sign + "";
43742 this.symbol = specifier.symbol === undefined ? "" : specifier.symbol + "";
43743 this.zero = !!specifier.zero;
43744 this.width = specifier.width === undefined ? undefined : +specifier.width;
43745 this.comma = !!specifier.comma;
43746 this.precision = specifier.precision === undefined ? undefined : +specifier.precision;
43747 this.trim = !!specifier.trim;
43748 this.type = specifier.type === undefined ? "" : specifier.type + "";
43751 FormatSpecifier.prototype.toString = function () {
43752 return this.fill + this.align + this.sign + this.symbol + (this.zero ? "0" : "") + (this.width === undefined ? "" : Math.max(1, this.width | 0)) + (this.comma ? "," : "") + (this.precision === undefined ? "" : "." + Math.max(0, this.precision | 0)) + (this.trim ? "~" : "") + this.type;
43755 // Trims insignificant zeros, e.g., replaces 1.2000k with 1.2k.
43756 function formatTrim (s) {
43757 out: for (var n = s.length, i = 1, i0 = -1, i1; i < n; ++i) {
43764 if (i0 === 0) i0 = i;
43769 if (!+s[i]) break out;
43770 if (i0 > 0) i0 = 0;
43775 return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s;
43779 var fails$3 = fails$N;
43780 var thisNumberValue = thisNumberValue$2;
43782 var nativeToPrecision = 1.0.toPrecision;
43784 var FORCED$1 = fails$3(function () {
43786 return nativeToPrecision.call(1, undefined) !== '1';
43787 }) || !fails$3(function () {
43788 // V8 ~ Android 4.3-
43789 nativeToPrecision.call({});
43792 // `Number.prototype.toPrecision` method
43793 // https://tc39.es/ecma262/#sec-number.prototype.toprecision
43794 $$7({ target: 'Number', proto: true, forced: FORCED$1 }, {
43795 toPrecision: function toPrecision(precision) {
43796 return precision === undefined
43797 ? nativeToPrecision.call(thisNumberValue(this))
43798 : nativeToPrecision.call(thisNumberValue(this), precision);
43802 var prefixExponent;
43803 function formatPrefixAuto (x, p) {
43804 var d = formatDecimalParts(x, p);
43805 if (!d) return x + "";
43806 var coefficient = d[0],
43808 i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
43809 n = coefficient.length;
43810 return i === n ? coefficient : i > n ? coefficient + new Array(i - n + 1).join("0") : i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i) : "0." + new Array(1 - i).join("0") + formatDecimalParts(x, Math.max(0, p + i - 1))[0]; // less than 1y!
43813 function formatRounded (x, p) {
43814 var d = formatDecimalParts(x, p);
43815 if (!d) return x + "";
43816 var coefficient = d[0],
43818 return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient : coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1) : coefficient + new Array(exponent - coefficient.length + 2).join("0");
43821 var formatTypes = {
43822 "%": function _(x, p) {
43823 return (x * 100).toFixed(p);
43825 "b": function b(x) {
43826 return Math.round(x).toString(2);
43828 "c": function c(x) {
43831 "d": formatDecimal,
43832 "e": function e(x, p) {
43833 return x.toExponential(p);
43835 "f": function f(x, p) {
43836 return x.toFixed(p);
43838 "g": function g(x, p) {
43839 return x.toPrecision(p);
43841 "o": function o(x) {
43842 return Math.round(x).toString(8);
43844 "p": function p(x, _p) {
43845 return formatRounded(x * 100, _p);
43847 "r": formatRounded,
43848 "s": formatPrefixAuto,
43849 "X": function X(x) {
43850 return Math.round(x).toString(16).toUpperCase();
43852 "x": function x(_x) {
43853 return Math.round(_x).toString(16);
43857 function identity (x) {
43861 var map$1 = Array.prototype.map,
43862 prefixes = ["y", "z", "a", "f", "p", "n", "µ", "m", "", "k", "M", "G", "T", "P", "E", "Z", "Y"];
43863 function formatLocale (locale) {
43864 var group = locale.grouping === undefined || locale.thousands === undefined ? identity : formatGroup(map$1.call(locale.grouping, Number), locale.thousands + ""),
43865 currencyPrefix = locale.currency === undefined ? "" : locale.currency[0] + "",
43866 currencySuffix = locale.currency === undefined ? "" : locale.currency[1] + "",
43867 decimal = locale.decimal === undefined ? "." : locale.decimal + "",
43868 numerals = locale.numerals === undefined ? identity : formatNumerals(map$1.call(locale.numerals, String)),
43869 percent = locale.percent === undefined ? "%" : locale.percent + "",
43870 minus = locale.minus === undefined ? "−" : locale.minus + "",
43871 nan = locale.nan === undefined ? "NaN" : locale.nan + "";
43873 function newFormat(specifier) {
43874 specifier = formatSpecifier(specifier);
43875 var fill = specifier.fill,
43876 align = specifier.align,
43877 sign = specifier.sign,
43878 symbol = specifier.symbol,
43879 zero = specifier.zero,
43880 width = specifier.width,
43881 comma = specifier.comma,
43882 precision = specifier.precision,
43883 trim = specifier.trim,
43884 type = specifier.type; // The "n" type is an alias for ",g".
43886 if (type === "n") comma = true, type = "g"; // The "" type, and any invalid type, is an alias for ".12~g".
43887 else if (!formatTypes[type]) precision === undefined && (precision = 12), trim = true, type = "g"; // If zero fill is specified, padding goes after sign and before digits.
43889 if (zero || fill === "0" && align === "=") zero = true, fill = "0", align = "="; // Compute the prefix and suffix.
43890 // For SI-prefix, the suffix is lazily computed.
43892 var prefix = symbol === "$" ? currencyPrefix : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
43893 suffix = symbol === "$" ? currencySuffix : /[%p]/.test(type) ? percent : ""; // What format function should we use?
43894 // Is this an integer type?
43895 // Can this type generate exponential notation?
43897 var formatType = formatTypes[type],
43898 maybeSuffix = /[defgprs%]/.test(type); // Set the default precision if not specified,
43899 // or clamp the specified precision to the supported range.
43900 // For significant precision, it must be in [1, 21].
43901 // For fixed precision, it must be in [0, 20].
43903 precision = precision === undefined ? 6 : /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision)) : Math.max(0, Math.min(20, precision));
43905 function format(value) {
43906 var valuePrefix = prefix,
43907 valueSuffix = suffix,
43912 if (type === "c") {
43913 valueSuffix = formatType(value) + valueSuffix;
43916 value = +value; // Determine the sign. -0 is not less than 0, but 1 / -0 is!
43918 var valueNegative = value < 0 || 1 / value < 0; // Perform the initial formatting.
43920 value = isNaN(value) ? nan : formatType(Math.abs(value), precision); // Trim insignificant zeros.
43922 if (trim) value = formatTrim(value); // If a negative value rounds to zero after formatting, and no explicit positive sign is requested, hide the sign.
43924 if (valueNegative && +value === 0 && sign !== "+") valueNegative = false; // Compute the prefix and suffix.
43926 valuePrefix = (valueNegative ? sign === "(" ? sign : minus : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
43927 valueSuffix = (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + valueSuffix + (valueNegative && sign === "(" ? ")" : ""); // Break the formatted value into the integer “value” part that can be
43928 // grouped, and fractional or exponential “suffix” part that is not.
43931 i = -1, n = value.length;
43934 if (c = value.charCodeAt(i), 48 > c || c > 57) {
43935 valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
43936 value = value.slice(0, i);
43941 } // If the fill character is not "0", grouping is applied before padding.
43944 if (comma && !zero) value = group(value, Infinity); // Compute the padding.
43946 var length = valuePrefix.length + value.length + valueSuffix.length,
43947 padding = length < width ? new Array(width - length + 1).join(fill) : ""; // If the fill character is "0", grouping is applied after padding.
43949 if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = ""; // Reconstruct the final output based on the desired alignment.
43953 value = valuePrefix + value + valueSuffix + padding;
43957 value = valuePrefix + padding + value + valueSuffix;
43961 value = padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
43965 value = padding + valuePrefix + value + valueSuffix;
43969 return numerals(value);
43972 format.toString = function () {
43973 return specifier + "";
43979 function formatPrefix(specifier, value) {
43980 var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
43981 e = Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3,
43982 k = Math.pow(10, -e),
43983 prefix = prefixes[8 + e / 3];
43984 return function (value) {
43985 return f(k * value) + prefix;
43991 formatPrefix: formatPrefix
44001 currency: ["$", ""]
44003 function defaultLocale(definition) {
44004 locale = formatLocale(definition);
44005 format$1 = locale.format;
44006 formatPrefix = locale.formatPrefix;
44010 function precisionFixed (step) {
44011 return Math.max(0, -exponent(Math.abs(step)));
44014 function precisionPrefix (step, value) {
44015 return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent(value) / 3))) * 3 - exponent(Math.abs(step)));
44018 function precisionRound (step, max) {
44019 step = Math.abs(step), max = Math.abs(max) - step;
44020 return Math.max(0, exponent(max) - exponent(step)) + 1;
44023 function tickFormat(start, stop, count, specifier) {
44024 var step = tickStep(start, stop, count),
44026 specifier = formatSpecifier(specifier == null ? ",f" : specifier);
44028 switch (specifier.type) {
44031 var value = Math.max(Math.abs(start), Math.abs(stop));
44032 if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
44033 return formatPrefix(specifier, value);
44042 if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
44049 if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
44054 return format$1(specifier);
44057 function linearish(scale) {
44058 var domain = scale.domain;
44060 scale.ticks = function (count) {
44062 return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
44065 scale.tickFormat = function (count, specifier) {
44067 return tickFormat(d[0], d[d.length - 1], count == null ? 10 : count, specifier);
44070 scale.nice = function (count) {
44071 if (count == null) count = 10;
44074 var i1 = d.length - 1;
44081 if (stop < start) {
44082 step = start, start = stop, stop = step;
44083 step = i0, i0 = i1, i1 = step;
44086 while (maxIter-- > 0) {
44087 step = tickIncrement(start, stop, count);
44089 if (step === prestep) {
44093 } else if (step > 0) {
44094 start = Math.floor(start / step) * step;
44095 stop = Math.ceil(stop / step) * step;
44096 } else if (step < 0) {
44097 start = Math.ceil(start * step) / step;
44098 stop = Math.floor(stop * step) / step;
44111 function linear() {
44112 var scale = continuous();
44114 scale.copy = function () {
44115 return copy(scale, linear());
44118 initRange.apply(scale, arguments);
44119 return linearish(scale);
44122 // eslint-disable-next-line es/no-math-expm1 -- safe
44123 var $expm1 = Math.expm1;
44124 var exp$1 = Math.exp;
44126 // `Math.expm1` method implementation
44127 // https://tc39.es/ecma262/#sec-math.expm1
44128 var mathExpm1 = (!$expm1
44130 || $expm1(10) > 22025.465794806719 || $expm1(10) < 22025.4657948067165168
44132 || $expm1(-2e-17) != -2e-17
44133 ) ? function expm1(x) {
44134 return (x = +x) == 0 ? x : x > -1e-6 && x < 1e-6 ? x + x * x / 2 : exp$1(x) - 1;
44137 function quantize() {
44145 function scale(x) {
44146 return x != null && x <= x ? range[bisectRight(domain, x, 0, n)] : unknown;
44149 function rescale() {
44151 domain = new Array(n);
44154 domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
44160 scale.domain = function (_) {
44163 return arguments.length ? ((_ref = _, _ref2 = _slicedToArray(_ref, 2), x0 = _ref2[0], x1 = _ref2[1], _ref), x0 = +x0, x1 = +x1, rescale()) : [x0, x1];
44166 scale.range = function (_) {
44167 return arguments.length ? (n = (range = Array.from(_)).length - 1, rescale()) : range.slice();
44170 scale.invertExtent = function (y) {
44171 var i = range.indexOf(y);
44172 return i < 0 ? [NaN, NaN] : i < 1 ? [x0, domain[0]] : i >= n ? [domain[n - 1], x1] : [domain[i - 1], domain[i]];
44175 scale.unknown = function (_) {
44176 return arguments.length ? (unknown = _, scale) : scale;
44179 scale.thresholds = function () {
44180 return domain.slice();
44183 scale.copy = function () {
44184 return quantize().domain([x0, x1]).range(range).unknown(unknown);
44187 return initRange.apply(linearish(scale), arguments);
44190 // https://github.com/tc39/proposal-string-pad-start-end
44191 var toLength$2 = toLength$q;
44192 var repeat$1 = stringRepeat;
44193 var requireObjectCoercible$2 = requireObjectCoercible$e;
44195 var ceil = Math.ceil;
44197 // `String.prototype.{ padStart, padEnd }` methods implementation
44198 var createMethod = function (IS_END) {
44199 return function ($this, maxLength, fillString) {
44200 var S = String(requireObjectCoercible$2($this));
44201 var stringLength = S.length;
44202 var fillStr = fillString === undefined ? ' ' : String(fillString);
44203 var intMaxLength = toLength$2(maxLength);
44204 var fillLen, stringFiller;
44205 if (intMaxLength <= stringLength || fillStr == '') return S;
44206 fillLen = intMaxLength - stringLength;
44207 stringFiller = repeat$1.call(fillStr, ceil(fillLen / fillStr.length));
44208 if (stringFiller.length > fillLen) stringFiller = stringFiller.slice(0, fillLen);
44209 return IS_END ? S + stringFiller : stringFiller + S;
44214 // `String.prototype.padStart` method
44215 // https://tc39.es/ecma262/#sec-string.prototype.padstart
44216 start: createMethod(false),
44217 // `String.prototype.padEnd` method
44218 // https://tc39.es/ecma262/#sec-string.prototype.padend
44219 end: createMethod(true)
44222 var fails$2 = fails$N;
44223 var padStart = stringPad.start;
44225 var abs$1 = Math.abs;
44226 var DatePrototype = Date.prototype;
44227 var getTime = DatePrototype.getTime;
44228 var nativeDateToISOString = DatePrototype.toISOString;
44230 // `Date.prototype.toISOString` method implementation
44231 // https://tc39.es/ecma262/#sec-date.prototype.toisostring
44232 // PhantomJS / old WebKit fails here:
44233 var dateToIsoString = (fails$2(function () {
44234 return nativeDateToISOString.call(new Date(-5e13 - 1)) != '0385-07-25T07:06:39.999Z';
44235 }) || !fails$2(function () {
44236 nativeDateToISOString.call(new Date(NaN));
44237 })) ? function toISOString() {
44238 if (!isFinite(getTime.call(this))) throw RangeError('Invalid time value');
44240 var year = date.getUTCFullYear();
44241 var milliseconds = date.getUTCMilliseconds();
44242 var sign = year < 0 ? '-' : year > 9999 ? '+' : '';
44243 return sign + padStart(abs$1(year), sign ? 6 : 4, 0) +
44244 '-' + padStart(date.getUTCMonth() + 1, 2, 0) +
44245 '-' + padStart(date.getUTCDate(), 2, 0) +
44246 'T' + padStart(date.getUTCHours(), 2, 0) +
44247 ':' + padStart(date.getUTCMinutes(), 2, 0) +
44248 ':' + padStart(date.getUTCSeconds(), 2, 0) +
44249 '.' + padStart(milliseconds, 3, 0) +
44251 } : nativeDateToISOString;
44254 var toISOString = dateToIsoString;
44256 // `Date.prototype.toISOString` method
44257 // https://tc39.es/ecma262/#sec-date.prototype.toisostring
44258 // PhantomJS / old WebKit has a broken implementations
44259 $$6({ target: 'Date', proto: true, forced: Date.prototype.toISOString !== toISOString }, {
44260 toISOString: toISOString
44263 function behaviorBreathe() {
44264 var duration = 800;
44266 var selector = '.selected.shadow, .selected .shadow';
44268 var _selected = select(null);
44276 function ratchetyInterpolator(a, b, steps, units) {
44279 var sample = quantize().domain([0, 1]).range(d3_quantize(d3_interpolateNumber(a, b), steps));
44280 return function (t) {
44281 return String(sample(t)) + (units || '');
44285 function reset(selection) {
44286 selection.style('stroke-opacity', null).style('stroke-width', null).style('fill-opacity', null).style('r', null);
44289 function setAnimationParams(transition, fromTo) {
44290 var toFrom = fromTo === 'from' ? 'to' : 'from';
44291 transition.styleTween('stroke-opacity', function (d) {
44292 return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
44293 }).styleTween('stroke-width', function (d) {
44294 return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
44295 }).styleTween('fill-opacity', function (d) {
44296 return ratchetyInterpolator(_params[d.id][toFrom].opacity, _params[d.id][fromTo].opacity, steps);
44297 }).styleTween('r', function (d) {
44298 return ratchetyInterpolator(_params[d.id][toFrom].width, _params[d.id][fromTo].width, steps, 'px');
44302 function calcAnimationParams(selection) {
44303 selection.call(reset).each(function (d) {
44304 var s = select(this);
44305 var tag = s.node().tagName;
44311 var width; // determine base opacity and width
44313 if (tag === 'circle') {
44314 opacity = parseFloat(s.style('fill-opacity') || 0.5);
44315 width = parseFloat(s.style('r') || 15.5);
44317 opacity = parseFloat(s.style('stroke-opacity') || 0.7);
44318 width = parseFloat(s.style('stroke-width') || 10);
44319 } // calculate from/to interpolation params..
44323 p.from.opacity = opacity * 0.6;
44324 p.to.opacity = opacity * 1.25;
44325 p.from.width = width * 0.7;
44326 p.to.width = width * (tag === 'circle' ? 1.5 : 1);
44331 function run(surface, fromTo) {
44332 var toFrom = fromTo === 'from' ? 'to' : 'from';
44333 var currSelected = surface.selectAll(selector);
44334 var currClassed = surface.attr('class');
44336 if (_done || currSelected.empty()) {
44337 _selected.call(reset);
44339 _selected = select(null);
44343 if (!fastDeepEqual(currSelected.data(), _selected.data()) || currClassed !== _classed) {
44344 _selected.call(reset);
44346 _classed = currClassed;
44347 _selected = currSelected.call(calcAnimationParams);
44350 var didCallNextRun = false;
44352 _selected.transition().duration(duration).call(setAnimationParams, fromTo).on('end', function () {
44353 // `end` event is called for each selected element, but we want
44354 // it to run only once
44355 if (!didCallNextRun) {
44356 surface.call(run, toFrom);
44357 didCallNextRun = true;
44358 } // if entity was deselected, remove breathe styling
44361 if (!select(this).classed('selected')) {
44362 reset(select(this));
44367 function behavior(surface) {
44369 _timer = timer(function () {
44370 // wait for elements to actually become selected
44371 if (surface.selectAll(selector).empty()) {
44375 surface.call(run, 'from');
44383 behavior.restartIfNeeded = function (surface) {
44384 if (_selected.empty()) {
44385 surface.call(run, 'from');
44393 behavior.off = function () {
44400 _selected.interrupt().call(reset);
44406 /* Creates a keybinding behavior for an operation */
44407 function behaviorOperation(context) {
44410 function keypress(d3_event) {
44411 // prevent operations during low zoom selection
44412 if (!context.map().withinEditableZoom()) return;
44413 if (_operation.availableForKeypress && !_operation.availableForKeypress()) return;
44414 d3_event.preventDefault();
44416 var disabled = _operation.disabled();
44419 context.ui().flash.duration(4000).iconName('#iD-operation-' + _operation.id).iconClass('operation disabled').label(_operation.tooltip)();
44421 context.ui().flash.duration(2000).iconName('#iD-operation-' + _operation.id).iconClass('operation').label(_operation.annotation() || _operation.title)();
44422 if (_operation.point) _operation.point(null);
44428 function behavior() {
44429 if (_operation && _operation.available()) {
44430 context.keybinding().on(_operation.keys, keypress);
44436 behavior.off = function () {
44437 context.keybinding().off(_operation.keys);
44440 behavior.which = function (_) {
44441 if (!arguments.length) return _operation;
44449 function operationCircularize(context, selectedIDs) {
44452 var _actions = selectedIDs.map(getAction).filter(Boolean);
44454 var _amount = _actions.length === 1 ? 'single' : 'multiple';
44456 var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
44460 function getAction(entityID) {
44461 var entity = context.entity(entityID);
44462 if (entity.type !== 'way' || new Set(entity.nodes).size <= 1) return null;
44465 _extent = entity.extent(context.graph());
44467 _extent = _extent.extend(entity.extent(context.graph()));
44470 return actionCircularize(entityID, context.projection);
44473 var operation = function operation() {
44474 if (!_actions.length) return;
44476 var combinedAction = function combinedAction(graph, t) {
44477 _actions.forEach(function (action) {
44478 if (!action.disabled(graph)) {
44479 graph = action(graph, t);
44486 combinedAction.transitionable = true;
44487 context.perform(combinedAction, operation.annotation());
44488 window.setTimeout(function () {
44489 context.validator().validate();
44490 }, 300); // after any transition
44493 operation.available = function () {
44494 return _actions.length && selectedIDs.length === _actions.length;
44495 }; // don't cache this because the visible extent could change
44498 operation.disabled = function () {
44499 if (!_actions.length) return '';
44501 var actionDisableds = _actions.map(function (action) {
44502 return action.disabled(context.graph());
44503 }).filter(Boolean);
44505 if (actionDisableds.length === _actions.length) {
44506 // none of the features can be circularized
44507 if (new Set(actionDisableds).size > 1) {
44508 return 'multiple_blockers';
44511 return actionDisableds[0];
44512 } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
44513 return 'too_large';
44514 } else if (someMissing()) {
44515 return 'not_downloaded';
44516 } else if (selectedIDs.some(context.hasHiddenConnections)) {
44517 return 'connected_to_hidden';
44522 function someMissing() {
44523 if (context.inIntro()) return false;
44524 var osm = context.connection();
44527 var missing = _coords.filter(function (loc) {
44528 return !osm.isDataLoaded(loc);
44531 if (missing.length) {
44532 missing.forEach(function (loc) {
44533 context.loadTileAtLoc(loc);
44543 operation.tooltip = function () {
44544 var disable = operation.disabled();
44545 return disable ? _t('operations.circularize.' + disable + '.' + _amount) : _t('operations.circularize.description.' + _amount);
44548 operation.annotation = function () {
44549 return _t('operations.circularize.annotation.feature', {
44554 operation.id = 'circularize';
44555 operation.keys = [_t('operations.circularize.key')];
44556 operation.title = _t('operations.circularize.title');
44557 operation.behavior = behaviorOperation(context).which(operation);
44561 // For example, ⌘Z -> Ctrl+Z
44563 var uiCmd = function uiCmd(code) {
44564 var detected = utilDetect();
44566 if (detected.os === 'mac') {
44570 if (detected.os === 'win') {
44571 if (code === '⌘⇧Z') return 'Ctrl+Y';
44583 for (var i = 0; i < code.length; i++) {
44584 if (code[i] in replacements) {
44585 result += replacements[code[i]] + (i < code.length - 1 ? '+' : '');
44592 }; // return a display-focused string for a given keyboard code
44594 uiCmd.display = function (code) {
44595 if (code.length !== 1) return code;
44596 var detected = utilDetect();
44597 var mac = detected.os === 'mac';
44598 var replacements = {
44599 '⌘': mac ? '⌘ ' + _t('shortcuts.key.cmd') : _t('shortcuts.key.ctrl'),
44600 '⇧': mac ? '⇧ ' + _t('shortcuts.key.shift') : _t('shortcuts.key.shift'),
44601 '⌥': mac ? '⌥ ' + _t('shortcuts.key.option') : _t('shortcuts.key.alt'),
44602 '⌃': mac ? '⌃ ' + _t('shortcuts.key.ctrl') : _t('shortcuts.key.ctrl'),
44603 '⌫': mac ? '⌫ ' + _t('shortcuts.key.delete') : _t('shortcuts.key.backspace'),
44604 '⌦': mac ? '⌦ ' + _t('shortcuts.key.del') : _t('shortcuts.key.del'),
44605 '↖': mac ? '↖ ' + _t('shortcuts.key.pgup') : _t('shortcuts.key.pgup'),
44606 '↘': mac ? '↘ ' + _t('shortcuts.key.pgdn') : _t('shortcuts.key.pgdn'),
44607 '⇞': mac ? '⇞ ' + _t('shortcuts.key.home') : _t('shortcuts.key.home'),
44608 '⇟': mac ? '⇟ ' + _t('shortcuts.key.end') : _t('shortcuts.key.end'),
44609 '↵': mac ? '⏎ ' + _t('shortcuts.key.return') : _t('shortcuts.key.enter'),
44610 '⎋': mac ? '⎋ ' + _t('shortcuts.key.esc') : _t('shortcuts.key.esc'),
44611 '☰': mac ? '☰ ' + _t('shortcuts.key.menu') : _t('shortcuts.key.menu')
44613 return replacements[code] || code;
44616 function operationDelete(context, selectedIDs) {
44617 var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44618 var action = actionDeleteMultiple(selectedIDs);
44619 var nodes = utilGetAllNodes(selectedIDs, context.graph());
44620 var coords = nodes.map(function (n) {
44623 var extent = utilTotalExtent(selectedIDs, context.graph());
44625 var operation = function operation() {
44626 var nextSelectedID;
44627 var nextSelectedLoc;
44629 if (selectedIDs.length === 1) {
44630 var id = selectedIDs[0];
44631 var entity = context.entity(id);
44632 var geometry = entity.geometry(context.graph());
44633 var parents = context.graph().parentWays(entity);
44634 var parent = parents[0]; // Select the next closest node in the way.
44636 if (geometry === 'vertex') {
44637 var nodes = parent.nodes;
44638 var i = nodes.indexOf(id);
44642 } else if (i === nodes.length - 1) {
44645 var a = geoSphericalDistance(entity.loc, context.entity(nodes[i - 1]).loc);
44646 var b = geoSphericalDistance(entity.loc, context.entity(nodes[i + 1]).loc);
44647 i = a < b ? i - 1 : i + 1;
44650 nextSelectedID = nodes[i];
44651 nextSelectedLoc = context.entity(nextSelectedID).loc;
44655 context.perform(action, operation.annotation());
44656 context.validator().validate();
44658 if (nextSelectedID && nextSelectedLoc) {
44659 if (context.hasEntity(nextSelectedID)) {
44660 context.enter(modeSelect(context, [nextSelectedID]).follow(true));
44662 context.map().centerEase(nextSelectedLoc);
44663 context.enter(modeBrowse(context));
44666 context.enter(modeBrowse(context));
44670 operation.available = function () {
44674 operation.disabled = function () {
44675 if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44676 return 'too_large';
44677 } else if (someMissing()) {
44678 return 'not_downloaded';
44679 } else if (selectedIDs.some(context.hasHiddenConnections)) {
44680 return 'connected_to_hidden';
44681 } else if (selectedIDs.some(protectedMember)) {
44682 return 'part_of_relation';
44683 } else if (selectedIDs.some(incompleteRelation)) {
44684 return 'incomplete_relation';
44685 } else if (selectedIDs.some(hasWikidataTag)) {
44686 return 'has_wikidata_tag';
44691 function someMissing() {
44692 if (context.inIntro()) return false;
44693 var osm = context.connection();
44696 var missing = coords.filter(function (loc) {
44697 return !osm.isDataLoaded(loc);
44700 if (missing.length) {
44701 missing.forEach(function (loc) {
44702 context.loadTileAtLoc(loc);
44711 function hasWikidataTag(id) {
44712 var entity = context.entity(id);
44713 return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
44716 function incompleteRelation(id) {
44717 var entity = context.entity(id);
44718 return entity.type === 'relation' && !entity.isComplete(context.graph());
44721 function protectedMember(id) {
44722 var entity = context.entity(id);
44723 if (entity.type !== 'way') return false;
44724 var parents = context.graph().parentRelations(entity);
44726 for (var i = 0; i < parents.length; i++) {
44727 var parent = parents[i];
44728 var type = parent.tags.type;
44729 var role = parent.memberById(id).role || 'outer';
44731 if (type === 'route' || type === 'boundary' || type === 'multipolygon' && role === 'outer') {
44740 operation.tooltip = function () {
44741 var disable = operation.disabled();
44742 return disable ? _t('operations.delete.' + disable + '.' + multi) : _t('operations.delete.description.' + multi);
44745 operation.annotation = function () {
44746 return selectedIDs.length === 1 ? _t('operations.delete.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.delete.annotation.feature', {
44747 n: selectedIDs.length
44751 operation.id = 'delete';
44752 operation.keys = [uiCmd('⌘⌫'), uiCmd('⌘⌦'), uiCmd('⌦')];
44753 operation.title = _t('operations.delete.title');
44754 operation.behavior = behaviorOperation(context).which(operation);
44758 function operationOrthogonalize(context, selectedIDs) {
44763 var _actions = selectedIDs.map(chooseAction).filter(Boolean);
44765 var _amount = _actions.length === 1 ? 'single' : 'multiple';
44767 var _coords = utilGetAllNodes(selectedIDs, context.graph()).map(function (n) {
44771 function chooseAction(entityID) {
44772 var entity = context.entity(entityID);
44773 var geometry = entity.geometry(context.graph());
44776 _extent = entity.extent(context.graph());
44778 _extent = _extent.extend(entity.extent(context.graph()));
44779 } // square a line/area
44782 if (entity.type === 'way' && new Set(entity.nodes).size > 2) {
44783 if (_type && _type !== 'feature') return null;
44785 return actionOrthogonalize(entityID, context.projection); // square a single vertex
44786 } else if (geometry === 'vertex') {
44787 if (_type && _type !== 'corner') return null;
44789 var graph = context.graph();
44790 var parents = graph.parentWays(entity);
44792 if (parents.length === 1) {
44793 var way = parents[0];
44795 if (way.nodes.indexOf(entityID) !== -1) {
44796 return actionOrthogonalize(way.id, context.projection, entityID);
44804 var operation = function operation() {
44805 if (!_actions.length) return;
44807 var combinedAction = function combinedAction(graph, t) {
44808 _actions.forEach(function (action) {
44809 if (!action.disabled(graph)) {
44810 graph = action(graph, t);
44817 combinedAction.transitionable = true;
44818 context.perform(combinedAction, operation.annotation());
44819 window.setTimeout(function () {
44820 context.validator().validate();
44821 }, 300); // after any transition
44824 operation.available = function () {
44825 return _actions.length && selectedIDs.length === _actions.length;
44826 }; // don't cache this because the visible extent could change
44829 operation.disabled = function () {
44830 if (!_actions.length) return '';
44832 var actionDisableds = _actions.map(function (action) {
44833 return action.disabled(context.graph());
44834 }).filter(Boolean);
44836 if (actionDisableds.length === _actions.length) {
44837 // none of the features can be squared
44838 if (new Set(actionDisableds).size > 1) {
44839 return 'multiple_blockers';
44842 return actionDisableds[0];
44843 } else if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
44844 return 'too_large';
44845 } else if (someMissing()) {
44846 return 'not_downloaded';
44847 } else if (selectedIDs.some(context.hasHiddenConnections)) {
44848 return 'connected_to_hidden';
44853 function someMissing() {
44854 if (context.inIntro()) return false;
44855 var osm = context.connection();
44858 var missing = _coords.filter(function (loc) {
44859 return !osm.isDataLoaded(loc);
44862 if (missing.length) {
44863 missing.forEach(function (loc) {
44864 context.loadTileAtLoc(loc);
44874 operation.tooltip = function () {
44875 var disable = operation.disabled();
44876 return disable ? _t('operations.orthogonalize.' + disable + '.' + _amount) : _t('operations.orthogonalize.description.' + _type + '.' + _amount);
44879 operation.annotation = function () {
44880 return _t('operations.orthogonalize.annotation.' + _type, {
44885 operation.id = 'orthogonalize';
44886 operation.keys = [_t('operations.orthogonalize.key')];
44887 operation.title = _t('operations.orthogonalize.title');
44888 operation.behavior = behaviorOperation(context).which(operation);
44892 function operationReflectShort(context, selectedIDs) {
44893 return operationReflect(context, selectedIDs, 'short');
44895 function operationReflectLong(context, selectedIDs) {
44896 return operationReflect(context, selectedIDs, 'long');
44898 function operationReflect(context, selectedIDs, axis) {
44899 axis = axis || 'long';
44900 var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44901 var nodes = utilGetAllNodes(selectedIDs, context.graph());
44902 var coords = nodes.map(function (n) {
44905 var extent = utilTotalExtent(selectedIDs, context.graph());
44907 var operation = function operation() {
44908 var action = actionReflect(selectedIDs, context.projection).useLongAxis(Boolean(axis === 'long'));
44909 context.perform(action, operation.annotation());
44910 window.setTimeout(function () {
44911 context.validator().validate();
44912 }, 300); // after any transition
44915 operation.available = function () {
44916 return nodes.length >= 3;
44917 }; // don't cache this because the visible extent could change
44920 operation.disabled = function () {
44921 if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44922 return 'too_large';
44923 } else if (someMissing()) {
44924 return 'not_downloaded';
44925 } else if (selectedIDs.some(context.hasHiddenConnections)) {
44926 return 'connected_to_hidden';
44927 } else if (selectedIDs.some(incompleteRelation)) {
44928 return 'incomplete_relation';
44933 function someMissing() {
44934 if (context.inIntro()) return false;
44935 var osm = context.connection();
44938 var missing = coords.filter(function (loc) {
44939 return !osm.isDataLoaded(loc);
44942 if (missing.length) {
44943 missing.forEach(function (loc) {
44944 context.loadTileAtLoc(loc);
44953 function incompleteRelation(id) {
44954 var entity = context.entity(id);
44955 return entity.type === 'relation' && !entity.isComplete(context.graph());
44959 operation.tooltip = function () {
44960 var disable = operation.disabled();
44961 return disable ? _t('operations.reflect.' + disable + '.' + multi) : _t('operations.reflect.description.' + axis + '.' + multi);
44964 operation.annotation = function () {
44965 return _t('operations.reflect.annotation.' + axis + '.feature', {
44966 n: selectedIDs.length
44970 operation.id = 'reflect-' + axis;
44971 operation.keys = [_t('operations.reflect.key.' + axis)];
44972 operation.title = _t('operations.reflect.title.' + axis);
44973 operation.behavior = behaviorOperation(context).which(operation);
44977 function operationMove(context, selectedIDs) {
44978 var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
44979 var nodes = utilGetAllNodes(selectedIDs, context.graph());
44980 var coords = nodes.map(function (n) {
44983 var extent = utilTotalExtent(selectedIDs, context.graph());
44985 var operation = function operation() {
44986 context.enter(modeMove(context, selectedIDs));
44989 operation.available = function () {
44990 return selectedIDs.length > 0;
44993 operation.disabled = function () {
44994 if (extent.percentContainedIn(context.map().extent()) < 0.8) {
44995 return 'too_large';
44996 } else if (someMissing()) {
44997 return 'not_downloaded';
44998 } else if (selectedIDs.some(context.hasHiddenConnections)) {
44999 return 'connected_to_hidden';
45000 } else if (selectedIDs.some(incompleteRelation)) {
45001 return 'incomplete_relation';
45006 function someMissing() {
45007 if (context.inIntro()) return false;
45008 var osm = context.connection();
45011 var missing = coords.filter(function (loc) {
45012 return !osm.isDataLoaded(loc);
45015 if (missing.length) {
45016 missing.forEach(function (loc) {
45017 context.loadTileAtLoc(loc);
45026 function incompleteRelation(id) {
45027 var entity = context.entity(id);
45028 return entity.type === 'relation' && !entity.isComplete(context.graph());
45032 operation.tooltip = function () {
45033 var disable = operation.disabled();
45034 return disable ? _t('operations.move.' + disable + '.' + multi) : _t('operations.move.description.' + multi);
45037 operation.annotation = function () {
45038 return selectedIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.move.annotation.feature', {
45039 n: selectedIDs.length
45043 operation.id = 'move';
45044 operation.keys = [_t('operations.move.key')];
45045 operation.title = _t('operations.move.title');
45046 operation.behavior = behaviorOperation(context).which(operation);
45047 operation.mouseOnly = true;
45051 function modeRotate(context, entityIDs) {
45052 var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeMove
45058 var keybinding = utilKeybinding('rotate');
45059 var behaviors = [behaviorEdit(context), operationCircularize(context, entityIDs).behavior, operationDelete(context, entityIDs).behavior, operationMove(context, entityIDs).behavior, operationOrthogonalize(context, entityIDs).behavior, operationReflectLong(context, entityIDs).behavior, operationReflectShort(context, entityIDs).behavior];
45060 var annotation = entityIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.rotate.annotation.feature', {
45061 n: entityIDs.length
45068 var _prevTransform;
45070 var _pivot; // use pointer events on supported platforms; fallback to mouse events
45073 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45075 function doRotate(d3_event) {
45078 if (context.graph() !== _prevGraph) {
45079 fn = context.perform;
45081 fn = context.replace;
45082 } // projection changed, recalculate _pivot
45085 var projection = context.projection;
45086 var currTransform = projection.transform();
45088 if (!_prevTransform || currTransform.k !== _prevTransform.k || currTransform.x !== _prevTransform.x || currTransform.y !== _prevTransform.y) {
45089 var nodes = utilGetAllNodes(entityIDs, context.graph());
45090 var points = nodes.map(function (n) {
45091 return projection(n.loc);
45093 _pivot = getPivot(points);
45094 _prevAngle = undefined;
45097 var currMouse = context.map().mouse(d3_event);
45098 var currAngle = Math.atan2(currMouse[1] - _pivot[1], currMouse[0] - _pivot[0]);
45099 if (typeof _prevAngle === 'undefined') _prevAngle = currAngle;
45100 var delta = currAngle - _prevAngle;
45101 fn(actionRotate(entityIDs, _pivot, delta, projection));
45102 _prevTransform = currTransform;
45103 _prevAngle = currAngle;
45104 _prevGraph = context.graph();
45107 function getPivot(points) {
45110 if (points.length === 1) {
45111 _pivot = points[0];
45112 } else if (points.length === 2) {
45113 _pivot = geoVecInterp(points[0], points[1], 0.5);
45115 var polygonHull = d3_polygonHull(points);
45117 if (polygonHull.length === 2) {
45118 _pivot = geoVecInterp(points[0], points[1], 0.5);
45120 _pivot = d3_polygonCentroid(d3_polygonHull(points));
45127 function finish(d3_event) {
45128 d3_event.stopPropagation();
45129 context.replace(actionNoop(), annotation);
45130 context.enter(modeSelect(context, entityIDs));
45133 function cancel() {
45134 if (_prevGraph) context.pop(); // remove the rotate
45136 context.enter(modeSelect(context, entityIDs));
45139 function undone() {
45140 context.enter(modeBrowse(context));
45143 mode.enter = function () {
45145 context.features().forceVisible(entityIDs);
45146 behaviors.forEach(context.install);
45148 context.surface().on(_pointerPrefix + 'down.modeRotate', function (d3_event) {
45149 downEvent = d3_event;
45151 select(window).on(_pointerPrefix + 'move.modeRotate', doRotate, true).on(_pointerPrefix + 'up.modeRotate', function (d3_event) {
45152 if (!downEvent) return;
45153 var mapNode = context.container().select('.main-map').node();
45154 var pointGetter = utilFastMouse(mapNode);
45155 var p1 = pointGetter(downEvent);
45156 var p2 = pointGetter(d3_event);
45157 var dist = geoVecLength(p1, p2);
45158 if (dist <= _tolerancePx) finish(d3_event);
45161 context.history().on('undone.modeRotate', undone);
45162 keybinding.on('⎋', cancel).on('↩', finish);
45163 select(document).call(keybinding);
45166 mode.exit = function () {
45167 behaviors.forEach(context.uninstall);
45168 context.surface().on(_pointerPrefix + 'down.modeRotate', null);
45169 select(window).on(_pointerPrefix + 'move.modeRotate', null, true).on(_pointerPrefix + 'up.modeRotate', null, true);
45170 context.history().on('undone.modeRotate', null);
45171 select(document).call(keybinding.unbind);
45172 context.features().forceVisible([]);
45175 mode.selectedIDs = function () {
45176 if (!arguments.length) return entityIDs; // no assign
45184 function operationRotate(context, selectedIDs) {
45185 var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
45186 var nodes = utilGetAllNodes(selectedIDs, context.graph());
45187 var coords = nodes.map(function (n) {
45190 var extent = utilTotalExtent(selectedIDs, context.graph());
45192 var operation = function operation() {
45193 context.enter(modeRotate(context, selectedIDs));
45196 operation.available = function () {
45197 return nodes.length >= 2;
45200 operation.disabled = function () {
45201 if (extent.percentContainedIn(context.map().extent()) < 0.8) {
45202 return 'too_large';
45203 } else if (someMissing()) {
45204 return 'not_downloaded';
45205 } else if (selectedIDs.some(context.hasHiddenConnections)) {
45206 return 'connected_to_hidden';
45207 } else if (selectedIDs.some(incompleteRelation)) {
45208 return 'incomplete_relation';
45213 function someMissing() {
45214 if (context.inIntro()) return false;
45215 var osm = context.connection();
45218 var missing = coords.filter(function (loc) {
45219 return !osm.isDataLoaded(loc);
45222 if (missing.length) {
45223 missing.forEach(function (loc) {
45224 context.loadTileAtLoc(loc);
45233 function incompleteRelation(id) {
45234 var entity = context.entity(id);
45235 return entity.type === 'relation' && !entity.isComplete(context.graph());
45239 operation.tooltip = function () {
45240 var disable = operation.disabled();
45241 return disable ? _t('operations.rotate.' + disable + '.' + multi) : _t('operations.rotate.description.' + multi);
45244 operation.annotation = function () {
45245 return selectedIDs.length === 1 ? _t('operations.rotate.annotation.' + context.graph().geometry(selectedIDs[0])) : _t('operations.rotate.annotation.feature', {
45246 n: selectedIDs.length
45250 operation.id = 'rotate';
45251 operation.keys = [_t('operations.rotate.key')];
45252 operation.title = _t('operations.rotate.title');
45253 operation.behavior = behaviorOperation(context).which(operation);
45254 operation.mouseOnly = true;
45258 function modeMove(context, entityIDs, baseGraph) {
45259 var _tolerancePx = 4; // see also behaviorDrag, behaviorSelect, modeRotate
45265 var keybinding = utilKeybinding('move');
45266 var behaviors = [behaviorEdit(context), operationCircularize(context, entityIDs).behavior, operationDelete(context, entityIDs).behavior, operationOrthogonalize(context, entityIDs).behavior, operationReflectLong(context, entityIDs).behavior, operationReflectShort(context, entityIDs).behavior, operationRotate(context, entityIDs).behavior];
45267 var annotation = entityIDs.length === 1 ? _t('operations.move.annotation.' + context.graph().geometry(entityIDs[0])) : _t('operations.move.annotation.feature', {
45268 n: entityIDs.length
45277 var _nudgeInterval; // use pointer events on supported platforms; fallback to mouse events
45280 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45282 function doMove(nudge) {
45283 nudge = nudge || [0, 0];
45286 if (_prevGraph !== context.graph()) {
45288 _origin = context.map().mouseCoordinates();
45289 fn = context.perform;
45291 fn = context.overwrite;
45294 var currMouse = context.map().mouse();
45295 var origMouse = context.projection(_origin);
45296 var delta = geoVecSubtract(geoVecSubtract(currMouse, origMouse), nudge);
45297 fn(actionMove(entityIDs, delta, context.projection, _cache));
45298 _prevGraph = context.graph();
45301 function startNudge(nudge) {
45302 if (_nudgeInterval) window.clearInterval(_nudgeInterval);
45303 _nudgeInterval = window.setInterval(function () {
45304 context.map().pan(nudge);
45309 function stopNudge() {
45310 if (_nudgeInterval) {
45311 window.clearInterval(_nudgeInterval);
45312 _nudgeInterval = null;
45318 var nudge = geoViewportEdge(context.map().mouse(), context.map().dimensions());
45327 function finish(d3_event) {
45328 d3_event.stopPropagation();
45329 context.replace(actionNoop(), annotation);
45330 context.enter(modeSelect(context, entityIDs));
45334 function cancel() {
45336 while (context.graph() !== baseGraph) {
45338 } // reset to baseGraph
45341 context.enter(modeBrowse(context));
45343 if (_prevGraph) context.pop(); // remove the move
45345 context.enter(modeSelect(context, entityIDs));
45351 function undone() {
45352 context.enter(modeBrowse(context));
45355 mode.enter = function () {
45356 _origin = context.map().mouseCoordinates();
45359 context.features().forceVisible(entityIDs);
45360 behaviors.forEach(context.install);
45362 context.surface().on(_pointerPrefix + 'down.modeMove', function (d3_event) {
45363 downEvent = d3_event;
45365 select(window).on(_pointerPrefix + 'move.modeMove', move, true).on(_pointerPrefix + 'up.modeMove', function (d3_event) {
45366 if (!downEvent) return;
45367 var mapNode = context.container().select('.main-map').node();
45368 var pointGetter = utilFastMouse(mapNode);
45369 var p1 = pointGetter(downEvent);
45370 var p2 = pointGetter(d3_event);
45371 var dist = geoVecLength(p1, p2);
45372 if (dist <= _tolerancePx) finish(d3_event);
45375 context.history().on('undone.modeMove', undone);
45376 keybinding.on('⎋', cancel).on('↩', finish);
45377 select(document).call(keybinding);
45380 mode.exit = function () {
45382 behaviors.forEach(function (behavior) {
45383 context.uninstall(behavior);
45385 context.surface().on(_pointerPrefix + 'down.modeMove', null);
45386 select(window).on(_pointerPrefix + 'move.modeMove', null, true).on(_pointerPrefix + 'up.modeMove', null, true);
45387 context.history().on('undone.modeMove', null);
45388 select(document).call(keybinding.unbind);
45389 context.features().forceVisible([]);
45392 mode.selectedIDs = function () {
45393 if (!arguments.length) return entityIDs; // no assign
45401 function behaviorPaste(context) {
45402 function doPaste(d3_event) {
45403 // prevent paste during low zoom selection
45404 if (!context.map().withinEditableZoom()) return;
45405 d3_event.preventDefault();
45406 var baseGraph = context.graph();
45407 var mouse = context.map().mouse();
45408 var projection = context.projection;
45409 var viewport = geoExtent(projection.clipExtent()).polygon();
45410 if (!geoPointInPolygon(mouse, viewport)) return;
45411 var oldIDs = context.copyIDs();
45412 if (!oldIDs.length) return;
45413 var extent = geoExtent();
45414 var oldGraph = context.copyGraph();
45416 var action = actionCopyEntities(oldIDs, oldGraph);
45417 context.perform(action);
45418 var copies = action.copies();
45419 var originals = new Set();
45420 Object.values(copies).forEach(function (entity) {
45421 originals.add(entity.id);
45424 for (var id in copies) {
45425 var oldEntity = oldGraph.entity(id);
45426 var newEntity = copies[id];
45428 extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
45431 var parents = context.graph().parentWays(newEntity);
45432 var parentCopied = parents.some(function (parent) {
45433 return originals.has(parent.id);
45436 if (!parentCopied) {
45437 newIDs.push(newEntity.id);
45439 } // Put pasted objects where mouse pointer is..
45442 var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
45443 var delta = geoVecSubtract(mouse, copyPoint);
45444 context.perform(actionMove(newIDs, delta, projection));
45445 context.enter(modeMove(context, newIDs, baseGraph));
45448 function behavior() {
45449 context.keybinding().on(uiCmd('⌘V'), doPaste);
45453 behavior.off = function () {
45454 context.keybinding().off(uiCmd('⌘V'));
45461 var repeat = stringRepeat;
45463 // `String.prototype.repeat` method
45464 // https://tc39.es/ecma262/#sec-string.prototype.repeat
45465 $$5({ target: 'String', proto: true }, {
45470 `behaviorDrag` is like `d3_behavior.drag`, with the following differences:
45472 * The `origin` function is expected to return an [x, y] tuple rather than an
45474 * The events are `start`, `move`, and `end`.
45475 (https://github.com/mbostock/d3/issues/563)
45476 * The `start` event is not dispatched until the first cursor movement occurs.
45477 (https://github.com/mbostock/d3/pull/368)
45478 * The `move` event has a `point` and `delta` [x, y] tuple properties rather
45479 than `x`, `y`, `dx`, and `dy` properties.
45480 * The `end` event is not dispatched if no movement occurs.
45481 * An `off` function is available that unbinds the drag's internal event handlers.
45484 function behaviorDrag() {
45485 var dispatch = dispatch$8('start', 'move', 'end'); // see also behaviorSelect
45487 var _tolerancePx = 1; // keep this low to facilitate pixel-perfect micromapping
45489 var _penTolerancePx = 4; // styluses can be touchy so require greater movement - #1981
45491 var _origin = null;
45492 var _selector = '';
45500 var _pointerId; // use pointer events on supported platforms; fallback to mouse events
45503 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
45505 var d3_event_userSelectProperty = utilPrefixCSSProperty('UserSelect');
45507 var d3_event_userSelectSuppress = function d3_event_userSelectSuppress() {
45508 var selection$1 = selection();
45509 var select = selection$1.style(d3_event_userSelectProperty);
45510 selection$1.style(d3_event_userSelectProperty, 'none');
45511 return function () {
45512 selection$1.style(d3_event_userSelectProperty, select);
45516 function pointerdown(d3_event) {
45517 if (_pointerId) return;
45518 _pointerId = d3_event.pointerId || 'mouse';
45519 _targetNode = this; // only force reflow once per drag
45521 var pointerLocGetter = utilFastMouse(_surface || _targetNode.parentNode);
45523 var startOrigin = pointerLocGetter(d3_event);
45524 var started = false;
45525 var selectEnable = d3_event_userSelectSuppress();
45526 select(window).on(_pointerPrefix + 'move.drag', pointermove).on(_pointerPrefix + 'up.drag pointercancel.drag', pointerup, true);
45529 offset = _origin.call(_targetNode, _targetEntity);
45530 offset = [offset[0] - startOrigin[0], offset[1] - startOrigin[1]];
45535 d3_event.stopPropagation();
45537 function pointermove(d3_event) {
45538 if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
45539 var p = pointerLocGetter(d3_event);
45542 var dist = geoVecLength(startOrigin, p);
45543 var tolerance = d3_event.pointerType === 'pen' ? _penTolerancePx : _tolerancePx; // don't start until the drag has actually moved somewhat
45545 if (dist < tolerance) return;
45547 dispatch.call('start', this, d3_event, _targetEntity); // Don't send a `move` event in the same cycle as `start` since dragging
45548 // a midpoint will convert the target to a node.
45551 d3_event.stopPropagation();
45552 d3_event.preventDefault();
45553 var dx = p[0] - startOrigin[0];
45554 var dy = p[1] - startOrigin[1];
45555 dispatch.call('move', this, d3_event, _targetEntity, [p[0] + offset[0], p[1] + offset[1]], [dx, dy]);
45559 function pointerup(d3_event) {
45560 if (_pointerId !== (d3_event.pointerId || 'mouse')) return;
45564 dispatch.call('end', this, d3_event, _targetEntity);
45565 d3_event.preventDefault();
45568 select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
45573 function behavior(selection) {
45574 var matchesSelector = utilPrefixDOMProperty('matchesSelector');
45575 var delegate = pointerdown;
45578 delegate = function delegate(d3_event) {
45580 var target = d3_event.target;
45582 for (; target && target !== root; target = target.parentNode) {
45583 var datum = target.__data__;
45584 _targetEntity = datum instanceof osmNote ? datum : datum && datum.properties && datum.properties.entity;
45586 if (_targetEntity && target[matchesSelector](_selector)) {
45587 return pointerdown.call(target, d3_event);
45593 selection.on(_pointerPrefix + 'down.drag' + _selector, delegate);
45596 behavior.off = function (selection) {
45597 selection.on(_pointerPrefix + 'down.drag' + _selector, null);
45600 behavior.selector = function (_) {
45601 if (!arguments.length) return _selector;
45606 behavior.origin = function (_) {
45607 if (!arguments.length) return _origin;
45612 behavior.cancel = function () {
45613 select(window).on(_pointerPrefix + 'move.drag', null).on(_pointerPrefix + 'up.drag pointercancel.drag', null);
45617 behavior.targetNode = function (_) {
45618 if (!arguments.length) return _targetNode;
45623 behavior.targetEntity = function (_) {
45624 if (!arguments.length) return _targetEntity;
45629 behavior.surface = function (_) {
45630 if (!arguments.length) return _surface;
45635 return utilRebind(behavior, dispatch, 'on');
45638 function modeDragNode(context) {
45643 var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover);
45644 var edit = behaviorEdit(context);
45646 var _nudgeInterval;
45648 var _restoreSelectedIDs = [];
45649 var _wasMidpoint = false;
45650 var _isCancelled = false;
45658 function startNudge(d3_event, entity, nudge) {
45659 if (_nudgeInterval) window.clearInterval(_nudgeInterval);
45660 _nudgeInterval = window.setInterval(function () {
45661 context.map().pan(nudge);
45662 doMove(d3_event, entity, nudge);
45666 function stopNudge() {
45667 if (_nudgeInterval) {
45668 window.clearInterval(_nudgeInterval);
45669 _nudgeInterval = null;
45673 function moveAnnotation(entity) {
45674 return _t('operations.move.annotation.' + entity.geometry(context.graph()));
45677 function connectAnnotation(nodeEntity, targetEntity) {
45678 var nodeGeometry = nodeEntity.geometry(context.graph());
45679 var targetGeometry = targetEntity.geometry(context.graph());
45681 if (nodeGeometry === 'vertex' && targetGeometry === 'vertex') {
45682 var nodeParentWayIDs = context.graph().parentWays(nodeEntity);
45683 var targetParentWayIDs = context.graph().parentWays(targetEntity);
45684 var sharedParentWays = utilArrayIntersection(nodeParentWayIDs, targetParentWayIDs); // if both vertices are part of the same way
45686 if (sharedParentWays.length !== 0) {
45687 // if the nodes are next to each other, they are merged
45688 if (sharedParentWays[0].areAdjacent(nodeEntity.id, targetEntity.id)) {
45689 return _t('operations.connect.annotation.from_vertex.to_adjacent_vertex');
45692 return _t('operations.connect.annotation.from_vertex.to_sibling_vertex');
45696 return _t('operations.connect.annotation.from_' + nodeGeometry + '.to_' + targetGeometry);
45699 function shouldSnapToNode(target) {
45700 if (!_activeEntity) return false;
45701 return _activeEntity.geometry(context.graph()) !== 'vertex' || target.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(target, context.graph());
45704 function origin(entity) {
45705 return context.projection(entity.loc);
45708 function keydown(d3_event) {
45709 if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
45710 if (context.surface().classed('nope')) {
45711 context.surface().classed('nope-suppressed', true);
45714 context.surface().classed('nope', false).classed('nope-disabled', true);
45718 function keyup(d3_event) {
45719 if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
45720 if (context.surface().classed('nope-suppressed')) {
45721 context.surface().classed('nope', true);
45724 context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
45728 function start(d3_event, entity) {
45729 _wasMidpoint = entity.type === 'midpoint';
45730 var hasHidden = context.features().hasHiddenConnections(entity, context.graph());
45731 _isCancelled = !context.editable() || d3_event.shiftKey || hasHidden;
45733 if (_isCancelled) {
45735 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('modes.drag_node.connected_to_hidden'))();
45738 return drag.cancel();
45741 if (_wasMidpoint) {
45742 var midpoint = entity;
45743 entity = osmNode();
45744 context.perform(actionAddMidpoint(midpoint, entity));
45745 entity = context.entity(entity.id); // get post-action entity
45747 var vertex = context.surface().selectAll('.' + entity.id);
45748 drag.targetNode(vertex.node()).targetEntity(entity);
45750 context.perform(actionNoop());
45753 _activeEntity = entity;
45754 _startLoc = entity.loc;
45755 hover.ignoreVertex(entity.geometry(context.graph()) === 'vertex');
45756 context.surface().selectAll('.' + _activeEntity.id).classed('active', true);
45757 context.enter(mode);
45759 // - `behavior/draw.js` `datum()`
45762 function datum(d3_event) {
45763 if (!d3_event || d3_event.altKey) {
45766 // When dragging, snap only to touch targets..
45767 // (this excludes area fills and active drawing elements)
45768 var d = d3_event.target.__data__;
45769 return d && d.properties && d.properties.target ? d : {};
45773 function doMove(d3_event, entity, nudge) {
45774 nudge = nudge || [0, 0];
45775 var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
45776 var currMouse = geoVecSubtract(currPoint, nudge);
45777 var loc = context.projection.invert(currMouse);
45780 if (!_nudgeInterval) {
45781 // If not nudging at the edge of the viewport, try to snap..
45783 // - `mode/drag_node.js` `doMove()`
45784 // - `behavior/draw.js` `click()`
45785 // - `behavior/draw_way.js` `move()`
45786 var d = datum(d3_event);
45787 target = d && d.properties && d.properties.entity;
45788 var targetLoc = target && target.loc;
45789 var targetNodes = d && d.properties && d.properties.nodes;
45792 // snap to node/vertex - a point target with `.loc`
45793 if (shouldSnapToNode(target)) {
45796 } else if (targetNodes) {
45797 // snap to way - a line target with `.nodes`
45798 edge = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, end.id);
45806 context.replace(actionMoveNode(entity.id, loc)); // Below here: validations
45808 var isInvalid = false; // Check if this connection to `target` could cause relations to break..
45811 isInvalid = hasRelationConflict(entity, target, edge, context.graph());
45812 } // Check if this drag causes the geometry to break..
45816 isInvalid = hasInvalidGeometry(entity, context.graph());
45819 var nope = context.surface().classed('nope');
45821 if (isInvalid === 'relation' || isInvalid === 'restriction') {
45823 // about to nope - show hint
45824 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.connect.' + isInvalid, {
45825 relation: _mainPresetIndex.item('type/restriction').name()
45828 } else if (isInvalid) {
45829 var errorID = isInvalid === 'line' ? 'lines' : 'areas';
45830 context.ui().flash.duration(3000).iconName('#iD-icon-no').label(_t('self_intersection.error.' + errorID))();
45833 // about to un-nope, remove hint
45834 context.ui().flash.duration(1).label('')();
45838 var nopeDisabled = context.surface().classed('nope-disabled');
45840 if (nopeDisabled) {
45841 context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
45843 context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
45847 } // Uses `actionConnect.disabled()` to know whether this connection is ok..
45850 function hasRelationConflict(entity, target, edge, graph) {
45851 var testGraph = graph.update(); // copy
45852 // if snapping to way - add midpoint there and consider that the target..
45855 var midpoint = osmNode();
45856 var action = actionAddMidpoint({
45858 edge: [target.nodes[edge.index - 1], target.nodes[edge.index]]
45860 testGraph = action(testGraph);
45862 } // can we connect to it?
45865 var ids = [entity.id, target.id];
45866 return actionConnect(ids).disabled(testGraph);
45869 function hasInvalidGeometry(entity, graph) {
45870 var parents = graph.parentWays(entity);
45873 for (i = 0; i < parents.length; i++) {
45874 var parent = parents[i];
45876 var activeIndex = null; // which multipolygon ring contains node being dragged
45877 // test any parent multipolygons for valid geometry
45879 var relations = graph.parentRelations(parent);
45881 for (j = 0; j < relations.length; j++) {
45882 if (!relations[j].isMultipolygon()) continue;
45883 var rings = osmJoinWays(relations[j].members, graph); // find active ring and test it for self intersections
45885 for (k = 0; k < rings.length; k++) {
45886 nodes = rings[k].nodes;
45888 if (nodes.find(function (n) {
45889 return n.id === entity.id;
45893 if (geoHasSelfIntersections(nodes, entity.id)) {
45894 return 'multipolygonMember';
45898 rings[k].coords = nodes.map(function (n) {
45901 } // test active ring for intersections with other rings in the multipolygon
45904 for (k = 0; k < rings.length; k++) {
45905 if (k === activeIndex) continue; // make sure active ring doesn't cross passive rings
45907 if (geoHasLineIntersections(rings[activeIndex].nodes, rings[k].nodes, entity.id)) {
45908 return 'multipolygonRing';
45911 } // If we still haven't tested this node's parent way for self-intersections.
45912 // (because it's not a member of a multipolygon), test it now.
45915 if (activeIndex === null) {
45916 nodes = parent.nodes.map(function (nodeID) {
45917 return graph.entity(nodeID);
45920 if (nodes.length && geoHasSelfIntersections(nodes, entity.id)) {
45921 return parent.geometry(graph);
45929 function move(d3_event, entity, point) {
45930 if (_isCancelled) return;
45931 d3_event.stopPropagation();
45932 context.surface().classed('nope-disabled', d3_event.altKey);
45933 _lastLoc = context.projection.invert(point);
45934 doMove(d3_event, entity);
45935 var nudge = geoViewportEdge(point, context.map().dimensions());
45938 startNudge(d3_event, entity, nudge);
45944 function end(d3_event, entity) {
45945 if (_isCancelled) return;
45946 var wasPoint = entity.geometry(context.graph()) === 'point';
45947 var d = datum(d3_event);
45948 var nope = d && d.properties && d.properties.nope || context.surface().classed('nope');
45949 var target = d && d.properties && d.properties.entity; // entity to snap to
45953 context.perform(_actionBounceBack(entity.id, _startLoc));
45954 } else if (target && target.type === 'way') {
45955 var choice = geoChooseEdge(context.graph().childNodes(target), context.map().mouse(), context.projection, entity.id);
45956 context.replace(actionAddMidpoint({
45958 edge: [target.nodes[choice.index - 1], target.nodes[choice.index]]
45959 }, entity), connectAnnotation(entity, target));
45960 } else if (target && target.type === 'node' && shouldSnapToNode(target)) {
45961 context.replace(actionConnect([target.id, entity.id]), connectAnnotation(entity, target));
45962 } else if (_wasMidpoint) {
45963 context.replace(actionNoop(), _t('operations.add.annotation.vertex'));
45965 context.replace(actionNoop(), moveAnnotation(entity));
45969 context.enter(modeSelect(context, [entity.id]));
45971 var reselection = _restoreSelectedIDs.filter(function (id) {
45972 return context.graph().hasEntity(id);
45975 if (reselection.length) {
45976 context.enter(modeSelect(context, reselection));
45978 context.enter(modeBrowse(context));
45983 function _actionBounceBack(nodeID, toLoc) {
45984 var moveNode = actionMoveNode(nodeID, toLoc);
45986 var action = function action(graph, t) {
45987 // last time through, pop off the bounceback perform.
45988 // it will then overwrite the initial perform with a moveNode that does nothing
45989 if (t === 1) context.pop();
45990 return moveNode(graph, t);
45993 action.transitionable = true;
45997 function cancel() {
45999 context.enter(modeBrowse(context));
46002 var drag = behaviorDrag().selector('.layer-touch.points .target').surface(context.container().select('.main-map').node()).origin(origin).on('start', start).on('move', move).on('end', end);
46004 mode.enter = function () {
46005 context.install(hover);
46006 context.install(edit);
46007 select(window).on('keydown.dragNode', keydown).on('keyup.dragNode', keyup);
46008 context.history().on('undone.drag-node', cancel);
46011 mode.exit = function () {
46012 context.ui().sidebar.hover.cancel();
46013 context.uninstall(hover);
46014 context.uninstall(edit);
46015 select(window).on('keydown.dragNode', null).on('keyup.dragNode', null);
46016 context.history().on('undone.drag-node', null);
46017 _activeEntity = null;
46018 context.surface().classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false).selectAll('.active').classed('active', false);
46022 mode.selectedIDs = function () {
46023 if (!arguments.length) return _activeEntity ? [_activeEntity.id] : []; // no assign
46028 mode.activeID = function () {
46029 if (!arguments.length) return _activeEntity && _activeEntity.id; // no assign
46034 mode.restoreSelectedIDs = function (_) {
46035 if (!arguments.length) return _restoreSelectedIDs;
46036 _restoreSelectedIDs = _;
46040 mode.behavior = drag;
46045 var NativePromise = nativePromiseConstructor;
46046 var fails$1 = fails$N;
46047 var getBuiltIn = getBuiltIn$9;
46048 var speciesConstructor = speciesConstructor$8;
46049 var promiseResolve = promiseResolve$2;
46050 var redefine = redefine$g.exports;
46052 // Safari bug https://bugs.webkit.org/show_bug.cgi?id=200829
46053 var NON_GENERIC = !!NativePromise && fails$1(function () {
46054 NativePromise.prototype['finally'].call({ then: function () { /* empty */ } }, function () { /* empty */ });
46057 // `Promise.prototype.finally` method
46058 // https://tc39.es/ecma262/#sec-promise.prototype.finally
46059 $$4({ target: 'Promise', proto: true, real: true, forced: NON_GENERIC }, {
46060 'finally': function (onFinally) {
46061 var C = speciesConstructor(this, getBuiltIn('Promise'));
46062 var isFunction = typeof onFinally == 'function';
46064 isFunction ? function (x) {
46065 return promiseResolve(C, onFinally()).then(function () { return x; });
46067 isFunction ? function (e) {
46068 return promiseResolve(C, onFinally()).then(function () { throw e; });
46074 // makes sure that native promise-based APIs `Promise#finally` properly works with patched `Promise#then`
46075 if (typeof NativePromise == 'function') {
46076 var method = getBuiltIn('Promise').prototype['finally'];
46077 if (NativePromise.prototype['finally'] !== method) {
46078 redefine(NativePromise.prototype, 'finally', method, { unsafe: true });
46082 function quickselect(arr, k, left, right, compare) {
46083 quickselectStep(arr, k, left || 0, right || arr.length - 1, compare || defaultCompare);
46086 function quickselectStep(arr, k, left, right, compare) {
46087 while (right > left) {
46088 if (right - left > 600) {
46089 var n = right - left + 1;
46090 var m = k - left + 1;
46091 var z = Math.log(n);
46092 var s = 0.5 * Math.exp(2 * z / 3);
46093 var sd = 0.5 * Math.sqrt(z * s * (n - s) / n) * (m - n / 2 < 0 ? -1 : 1);
46094 var newLeft = Math.max(left, Math.floor(k - m * s / n + sd));
46095 var newRight = Math.min(right, Math.floor(k + (n - m) * s / n + sd));
46096 quickselectStep(arr, k, newLeft, newRight, compare);
46102 swap(arr, left, k);
46103 if (compare(arr[right], t) > 0) swap(arr, left, right);
46110 while (compare(arr[i], t) < 0) {
46114 while (compare(arr[j], t) > 0) {
46119 if (compare(arr[left], t) === 0) swap(arr, left, j);else {
46121 swap(arr, j, right);
46123 if (j <= k) left = j + 1;
46124 if (k <= j) right = j - 1;
46128 function swap(arr, i, j) {
46134 function defaultCompare(a, b) {
46135 return a < b ? -1 : a > b ? 1 : 0;
46138 var RBush = /*#__PURE__*/function () {
46140 var maxEntries = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 9;
46142 _classCallCheck$1(this, RBush);
46144 // max entries in a node is 9 by default; min node fill is 40% for best performance
46145 this._maxEntries = Math.max(4, maxEntries);
46146 this._minEntries = Math.max(2, Math.ceil(this._maxEntries * 0.4));
46150 _createClass$1(RBush, [{
46152 value: function all() {
46153 return this._all(this.data, []);
46157 value: function search(bbox) {
46158 var node = this.data;
46160 if (!intersects(bbox, node)) return result;
46161 var toBBox = this.toBBox;
46162 var nodesToSearch = [];
46165 for (var i = 0; i < node.children.length; i++) {
46166 var child = node.children[i];
46167 var childBBox = node.leaf ? toBBox(child) : child;
46169 if (intersects(bbox, childBBox)) {
46170 if (node.leaf) result.push(child);else if (contains(bbox, childBBox)) this._all(child, result);else nodesToSearch.push(child);
46174 node = nodesToSearch.pop();
46181 value: function collides(bbox) {
46182 var node = this.data;
46183 if (!intersects(bbox, node)) return false;
46184 var nodesToSearch = [];
46187 for (var i = 0; i < node.children.length; i++) {
46188 var child = node.children[i];
46189 var childBBox = node.leaf ? this.toBBox(child) : child;
46191 if (intersects(bbox, childBBox)) {
46192 if (node.leaf || contains(bbox, childBBox)) return true;
46193 nodesToSearch.push(child);
46197 node = nodesToSearch.pop();
46204 value: function load(data) {
46205 if (!(data && data.length)) return this;
46207 if (data.length < this._minEntries) {
46208 for (var i = 0; i < data.length; i++) {
46209 this.insert(data[i]);
46213 } // recursively build the tree with the given data from scratch using OMT algorithm
46216 var node = this._build(data.slice(), 0, data.length - 1, 0);
46218 if (!this.data.children.length) {
46219 // save as is if tree is empty
46221 } else if (this.data.height === node.height) {
46222 // split root if trees have the same height
46223 this._splitRoot(this.data, node);
46225 if (this.data.height < node.height) {
46226 // swap trees if inserted one is bigger
46227 var tmpNode = this.data;
46230 } // insert the small tree into the large tree at appropriate level
46233 this._insert(node, this.data.height - node.height - 1, true);
46240 value: function insert(item) {
46241 if (item) this._insert(item, this.data.height - 1);
46246 value: function clear() {
46247 this.data = createNode([]);
46252 value: function remove(item, equalsFn) {
46253 if (!item) return this;
46254 var node = this.data;
46255 var bbox = this.toBBox(item);
46258 var i, parent, goingUp; // depth-first iterative tree traversal
46260 while (node || path.length) {
46264 parent = path[path.length - 1];
46270 // check current node
46271 var index = findItem(item, node.children, equalsFn);
46273 if (index !== -1) {
46274 // item found, remove the item and condense tree upwards
46275 node.children.splice(index, 1);
46278 this._condense(path);
46284 if (!goingUp && !node.leaf && contains(node, bbox)) {
46290 node = node.children[0];
46291 } else if (parent) {
46294 node = parent.children[i];
46296 } else node = null; // nothing found
46304 value: function toBBox(item) {
46308 key: "compareMinX",
46309 value: function compareMinX(a, b) {
46310 return a.minX - b.minX;
46313 key: "compareMinY",
46314 value: function compareMinY(a, b) {
46315 return a.minY - b.minY;
46319 value: function toJSON() {
46324 value: function fromJSON(data) {
46330 value: function _all(node, result) {
46331 var nodesToSearch = [];
46334 if (node.leaf) result.push.apply(result, _toConsumableArray(node.children));else nodesToSearch.push.apply(nodesToSearch, _toConsumableArray(node.children));
46335 node = nodesToSearch.pop();
46342 value: function _build(items, left, right, height) {
46343 var N = right - left + 1;
46344 var M = this._maxEntries;
46348 // reached leaf level; return leaf
46349 node = createNode(items.slice(left, right + 1));
46350 calcBBox(node, this.toBBox);
46355 // target height of the bulk-loaded tree
46356 height = Math.ceil(Math.log(N) / Math.log(M)); // target number of root entries to maximize storage utilization
46358 M = Math.ceil(N / Math.pow(M, height - 1));
46361 node = createNode([]);
46363 node.height = height; // split the items into M mostly square tiles
46365 var N2 = Math.ceil(N / M);
46366 var N1 = N2 * Math.ceil(Math.sqrt(M));
46367 multiSelect(items, left, right, N1, this.compareMinX);
46369 for (var i = left; i <= right; i += N1) {
46370 var right2 = Math.min(i + N1 - 1, right);
46371 multiSelect(items, i, right2, N2, this.compareMinY);
46373 for (var j = i; j <= right2; j += N2) {
46374 var right3 = Math.min(j + N2 - 1, right2); // pack each entry recursively
46376 node.children.push(this._build(items, j, right3, height - 1));
46380 calcBBox(node, this.toBBox);
46384 key: "_chooseSubtree",
46385 value: function _chooseSubtree(bbox, node, level, path) {
46388 if (node.leaf || path.length - 1 === level) break;
46389 var minArea = Infinity;
46390 var minEnlargement = Infinity;
46391 var targetNode = void 0;
46393 for (var i = 0; i < node.children.length; i++) {
46394 var child = node.children[i];
46395 var area = bboxArea(child);
46396 var enlargement = enlargedArea(bbox, child) - area; // choose entry with the least area enlargement
46398 if (enlargement < minEnlargement) {
46399 minEnlargement = enlargement;
46400 minArea = area < minArea ? area : minArea;
46401 targetNode = child;
46402 } else if (enlargement === minEnlargement) {
46403 // otherwise choose one with the smallest area
46404 if (area < minArea) {
46406 targetNode = child;
46411 node = targetNode || node.children[0];
46418 value: function _insert(item, level, isNode) {
46419 var bbox = isNode ? item : this.toBBox(item);
46420 var insertPath = []; // find the best node for accommodating the item, saving all nodes along the path too
46422 var node = this._chooseSubtree(bbox, this.data, level, insertPath); // put the item into the node
46425 node.children.push(item);
46426 extend$1(node, bbox); // split on node overflow; propagate upwards if necessary
46428 while (level >= 0) {
46429 if (insertPath[level].children.length > this._maxEntries) {
46430 this._split(insertPath, level);
46434 } // adjust bboxes along the insertion path
46437 this._adjustParentBBoxes(bbox, insertPath, level);
46438 } // split overflowed node into two
46442 value: function _split(insertPath, level) {
46443 var node = insertPath[level];
46444 var M = node.children.length;
46445 var m = this._minEntries;
46447 this._chooseSplitAxis(node, m, M);
46449 var splitIndex = this._chooseSplitIndex(node, m, M);
46451 var newNode = createNode(node.children.splice(splitIndex, node.children.length - splitIndex));
46452 newNode.height = node.height;
46453 newNode.leaf = node.leaf;
46454 calcBBox(node, this.toBBox);
46455 calcBBox(newNode, this.toBBox);
46456 if (level) insertPath[level - 1].children.push(newNode);else this._splitRoot(node, newNode);
46460 value: function _splitRoot(node, newNode) {
46462 this.data = createNode([node, newNode]);
46463 this.data.height = node.height + 1;
46464 this.data.leaf = false;
46465 calcBBox(this.data, this.toBBox);
46468 key: "_chooseSplitIndex",
46469 value: function _chooseSplitIndex(node, m, M) {
46471 var minOverlap = Infinity;
46472 var minArea = Infinity;
46474 for (var i = m; i <= M - m; i++) {
46475 var bbox1 = distBBox(node, 0, i, this.toBBox);
46476 var bbox2 = distBBox(node, i, M, this.toBBox);
46477 var overlap = intersectionArea(bbox1, bbox2);
46478 var area = bboxArea(bbox1) + bboxArea(bbox2); // choose distribution with minimum overlap
46480 if (overlap < minOverlap) {
46481 minOverlap = overlap;
46483 minArea = area < minArea ? area : minArea;
46484 } else if (overlap === minOverlap) {
46485 // otherwise choose distribution with minimum area
46486 if (area < minArea) {
46493 return index || M - m;
46494 } // sorts node children by the best axis for split
46497 key: "_chooseSplitAxis",
46498 value: function _chooseSplitAxis(node, m, M) {
46499 var compareMinX = node.leaf ? this.compareMinX : compareNodeMinX;
46500 var compareMinY = node.leaf ? this.compareMinY : compareNodeMinY;
46502 var xMargin = this._allDistMargin(node, m, M, compareMinX);
46504 var yMargin = this._allDistMargin(node, m, M, compareMinY); // if total distributions margin value is minimal for x, sort by minX,
46505 // otherwise it's already sorted by minY
46508 if (xMargin < yMargin) node.children.sort(compareMinX);
46509 } // total margin of all possible split distributions where each node is at least m full
46512 key: "_allDistMargin",
46513 value: function _allDistMargin(node, m, M, compare) {
46514 node.children.sort(compare);
46515 var toBBox = this.toBBox;
46516 var leftBBox = distBBox(node, 0, m, toBBox);
46517 var rightBBox = distBBox(node, M - m, M, toBBox);
46518 var margin = bboxMargin(leftBBox) + bboxMargin(rightBBox);
46520 for (var i = m; i < M - m; i++) {
46521 var child = node.children[i];
46522 extend$1(leftBBox, node.leaf ? toBBox(child) : child);
46523 margin += bboxMargin(leftBBox);
46526 for (var _i = M - m - 1; _i >= m; _i--) {
46527 var _child = node.children[_i];
46528 extend$1(rightBBox, node.leaf ? toBBox(_child) : _child);
46529 margin += bboxMargin(rightBBox);
46535 key: "_adjustParentBBoxes",
46536 value: function _adjustParentBBoxes(bbox, path, level) {
46537 // adjust bboxes along the given tree path
46538 for (var i = level; i >= 0; i--) {
46539 extend$1(path[i], bbox);
46544 value: function _condense(path) {
46545 // go through the path, removing empty nodes and updating bboxes
46546 for (var i = path.length - 1, siblings; i >= 0; i--) {
46547 if (path[i].children.length === 0) {
46549 siblings = path[i - 1].children;
46550 siblings.splice(siblings.indexOf(path[i]), 1);
46551 } else this.clear();
46552 } else calcBBox(path[i], this.toBBox);
46560 function findItem(item, items, equalsFn) {
46561 if (!equalsFn) return items.indexOf(item);
46563 for (var i = 0; i < items.length; i++) {
46564 if (equalsFn(item, items[i])) return i;
46568 } // calculate node's bbox from bboxes of its children
46571 function calcBBox(node, toBBox) {
46572 distBBox(node, 0, node.children.length, toBBox, node);
46573 } // min bounding rectangle of node children from k to p-1
46576 function distBBox(node, k, p, toBBox, destNode) {
46577 if (!destNode) destNode = createNode(null);
46578 destNode.minX = Infinity;
46579 destNode.minY = Infinity;
46580 destNode.maxX = -Infinity;
46581 destNode.maxY = -Infinity;
46583 for (var i = k; i < p; i++) {
46584 var child = node.children[i];
46585 extend$1(destNode, node.leaf ? toBBox(child) : child);
46591 function extend$1(a, b) {
46592 a.minX = Math.min(a.minX, b.minX);
46593 a.minY = Math.min(a.minY, b.minY);
46594 a.maxX = Math.max(a.maxX, b.maxX);
46595 a.maxY = Math.max(a.maxY, b.maxY);
46599 function compareNodeMinX(a, b) {
46600 return a.minX - b.minX;
46603 function compareNodeMinY(a, b) {
46604 return a.minY - b.minY;
46607 function bboxArea(a) {
46608 return (a.maxX - a.minX) * (a.maxY - a.minY);
46611 function bboxMargin(a) {
46612 return a.maxX - a.minX + (a.maxY - a.minY);
46615 function enlargedArea(a, b) {
46616 return (Math.max(b.maxX, a.maxX) - Math.min(b.minX, a.minX)) * (Math.max(b.maxY, a.maxY) - Math.min(b.minY, a.minY));
46619 function intersectionArea(a, b) {
46620 var minX = Math.max(a.minX, b.minX);
46621 var minY = Math.max(a.minY, b.minY);
46622 var maxX = Math.min(a.maxX, b.maxX);
46623 var maxY = Math.min(a.maxY, b.maxY);
46624 return Math.max(0, maxX - minX) * Math.max(0, maxY - minY);
46627 function contains(a, b) {
46628 return a.minX <= b.minX && a.minY <= b.minY && b.maxX <= a.maxX && b.maxY <= a.maxY;
46631 function intersects(a, b) {
46632 return b.minX <= a.maxX && b.minY <= a.maxY && b.maxX >= a.minX && b.maxY >= a.minY;
46635 function createNode(children) {
46637 children: children,
46645 } // sort an array so that items come in groups of n unsorted items, with groups sorted between each other;
46646 // combines selection algorithm with binary divide & conquer approach
46649 function multiSelect(arr, left, right, n, compare) {
46650 var stack = [left, right];
46652 while (stack.length) {
46653 right = stack.pop();
46654 left = stack.pop();
46655 if (right - left <= n) continue;
46656 var mid = left + Math.ceil((right - left) / n / 2) * n;
46657 quickselect(arr, mid, left, right, compare);
46658 stack.push(left, mid, mid, right);
46662 function responseText(response) {
46663 if (!response.ok) throw new Error(response.status + " " + response.statusText);
46664 return response.text();
46667 function d3_text (input, init) {
46668 return fetch(input, init).then(responseText);
46671 function responseJson(response) {
46672 if (!response.ok) throw new Error(response.status + " " + response.statusText);
46673 if (response.status === 204 || response.status === 205) return;
46674 return response.json();
46677 function d3_json (input, init) {
46678 return fetch(input, init).then(responseJson);
46681 function parser(type) {
46682 return function (input, init) {
46683 return d3_text(input, init).then(function (text) {
46684 return new DOMParser().parseFromString(text, type);
46689 var d3_xml = parser("application/xml");
46690 var svg = parser("image/svg+xml");
46692 var tiler$6 = utilTiler();
46693 var dispatch$7 = dispatch$8('loaded');
46694 var _tileZoom$3 = 14;
46695 var _krUrlRoot = 'https://www.keepright.at';
46698 localizeStrings: {}
46699 }; // This gets reassigned if reset
46703 var _krRuleset = [// no 20 - multiple node on same spot - these are mostly boundaries overlapping roads
46704 30, 40, 50, 60, 70, 90, 100, 110, 120, 130, 150, 160, 170, 180, 190, 191, 192, 193, 194, 195, 196, 197, 198, 200, 201, 202, 203, 204, 205, 206, 207, 208, 210, 220, 230, 231, 232, 270, 280, 281, 282, 283, 284, 285, 290, 291, 292, 293, 294, 295, 296, 297, 298, 300, 310, 311, 312, 313, 320, 350, 360, 370, 380, 390, 400, 401, 402, 410, 411, 412, 413];
46706 function abortRequest$6(controller) {
46708 controller.abort();
46712 function abortUnwantedRequests$3(cache, tiles) {
46713 Object.keys(cache.inflightTile).forEach(function (k) {
46714 var wanted = tiles.find(function (tile) {
46715 return k === tile.id;
46719 abortRequest$6(cache.inflightTile[k]);
46720 delete cache.inflightTile[k];
46725 function encodeIssueRtree$2(d) {
46733 } // Replace or remove QAItem from rtree
46736 function updateRtree$3(item, replace) {
46737 _cache$2.rtree.remove(item, function (a, b) {
46738 return a.data.id === b.data.id;
46742 _cache$2.rtree.insert(item);
46746 function tokenReplacements(d) {
46747 if (!(d instanceof QAItem)) return;
46748 var htmlRegex = new RegExp(/<\/[a-z][\s\S]*>/);
46749 var replacements = {};
46750 var issueTemplate = _krData.errorTypes[d.whichType];
46752 if (!issueTemplate) {
46753 /* eslint-disable no-console */
46754 console.log('No Template: ', d.whichType);
46755 console.log(' ', d.description);
46756 /* eslint-enable no-console */
46759 } // some descriptions are just fixed text
46762 if (!issueTemplate.regex) return; // regex pattern should match description with variable details captured
46764 var errorRegex = new RegExp(issueTemplate.regex, 'i');
46765 var errorMatch = errorRegex.exec(d.description);
46768 /* eslint-disable no-console */
46769 console.log('Unmatched: ', d.whichType);
46770 console.log(' ', d.description);
46771 console.log(' ', errorRegex);
46772 /* eslint-enable no-console */
46777 for (var i = 1; i < errorMatch.length; i++) {
46779 var capture = errorMatch[i];
46780 var idType = void 0;
46781 idType = 'IDs' in issueTemplate ? issueTemplate.IDs[i - 1] : '';
46783 if (idType && capture) {
46784 // link IDs if present in the capture
46785 capture = parseError(capture, idType);
46786 } else if (htmlRegex.test(capture)) {
46787 // escape any html in non-IDs
46788 capture = '\\' + capture + '\\';
46790 var compare = capture.toLowerCase();
46792 if (_krData.localizeStrings[compare]) {
46793 // some replacement strings can be localized
46794 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
46798 replacements['var' + i] = capture;
46801 return replacements;
46804 function parseError(capture, idType) {
46805 var compare = capture.toLowerCase();
46807 if (_krData.localizeStrings[compare]) {
46808 // some replacement strings can be localized
46809 capture = _t('QA.keepRight.error_parts.' + _krData.localizeStrings[compare]);
46813 // link a string like "this node"
46815 capture = linkErrorObject(capture);
46819 capture = linkURL(capture);
46821 // link an entity ID
46826 capture = linkEntity(idType + capture);
46828 // some errors have more complex ID lists/variance
46831 capture = parse20(capture);
46835 capture = parse211(capture);
46839 capture = parse231(capture);
46843 capture = parse294(capture);
46847 capture = parse370(capture);
46853 function linkErrorObject(d) {
46854 return "<a class=\"error_object_link\">".concat(d, "</a>");
46857 function linkEntity(d) {
46858 return "<a class=\"error_entity_link\">".concat(d, "</a>");
46861 function linkURL(d) {
46862 return "<a class=\"kr_external_link\" target=\"_blank\" href=\"".concat(d, "\">").concat(d, "</a>");
46863 } // arbitrary node list of form: #ID, #ID, #ID...
46866 function parse211(capture) {
46868 var items = capture.split(', ');
46869 items.forEach(function (item) {
46870 // ID has # at the front
46871 var id = linkEntity('n' + item.slice(1));
46874 return newList.join(', ');
46875 } // arbitrary way list of form: #ID(layer),#ID(layer),#ID(layer)...
46878 function parse231(capture) {
46879 var newList = []; // unfortunately 'layer' can itself contain commas, so we split on '),'
46881 var items = capture.split('),');
46882 items.forEach(function (item) {
46883 var match = item.match(/\#(\d+)\((.+)\)?/);
46885 if (match !== null && match.length > 2) {
46886 newList.push(linkEntity('w' + match[1]) + ' ' + _t('QA.keepRight.errorTypes.231.layer', {
46891 return newList.join(', ');
46892 } // arbitrary node/relation list of form: from node #ID,to relation #ID,to node #ID...
46895 function parse294(capture) {
46897 var items = capture.split(',');
46898 items.forEach(function (item) {
46899 // item of form "from/to node/relation #ID"
46900 item = item.split(' '); // to/from role is more clear in quotes
46902 var role = "\"".concat(item[0], "\""); // first letter of node/relation provides the type
46904 var idType = item[1].slice(0, 1); // ID has # at the front
46906 var id = item[2].slice(1);
46907 id = linkEntity(idType + id);
46908 newList.push("".concat(role, " ").concat(item[1], " ").concat(id));
46910 return newList.join(', ');
46911 } // may or may not include the string "(including the name 'name')"
46914 function parse370(capture) {
46915 if (!capture) return '';
46916 var match = capture.match(/\(including the name (\'.+\')\)/);
46918 if (match && match.length) {
46919 return _t('QA.keepRight.errorTypes.370.including_the_name', {
46925 } // arbitrary node list of form: #ID,#ID,#ID...
46928 function parse20(capture) {
46930 var items = capture.split(',');
46931 items.forEach(function (item) {
46932 // ID has # at the front
46933 var id = linkEntity('n' + item.slice(1));
46936 return newList.join(', ');
46940 var serviceKeepRight = {
46941 title: 'keepRight',
46942 init: function init() {
46943 _mainFileFetcher.get('keepRight').then(function (d) {
46944 return _krData = d;
46951 this.event = utilRebind(this, dispatch$7, 'on');
46953 reset: function reset() {
46955 Object.values(_cache$2.inflightTile).forEach(abortRequest$6);
46967 // KeepRight API: http://osm.mueschelsoft.de/keepright/interfacing.php
46968 loadIssues: function loadIssues(projection) {
46974 }; // determine the needed tiles to cover the view
46976 var tiles = tiler$6.zoomExtent([_tileZoom$3, _tileZoom$3]).getTiles(projection); // abort inflight requests that are no longer needed
46978 abortUnwantedRequests$3(_cache$2, tiles); // issue new requests..
46980 tiles.forEach(function (tile) {
46981 if (_cache$2.loadedTile[tile.id] || _cache$2.inflightTile[tile.id]) return;
46983 var _tile$extent$rectangl = tile.extent.rectangle(),
46984 _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
46985 left = _tile$extent$rectangl2[0],
46986 top = _tile$extent$rectangl2[1],
46987 right = _tile$extent$rectangl2[2],
46988 bottom = _tile$extent$rectangl2[3];
46990 var params = Object.assign({}, options, {
46996 var url = "".concat(_krUrlRoot, "/export.php?") + utilQsString(params);
46997 var controller = new AbortController();
46998 _cache$2.inflightTile[tile.id] = controller;
47000 signal: controller.signal
47001 }).then(function (data) {
47002 delete _cache$2.inflightTile[tile.id];
47003 _cache$2.loadedTile[tile.id] = true;
47005 if (!data || !data.features || !data.features.length) {
47006 throw new Error('No Data');
47009 data.features.forEach(function (feature) {
47010 var _feature$properties = feature.properties,
47011 itemType = _feature$properties.error_type,
47012 id = _feature$properties.error_id,
47013 _feature$properties$c = _feature$properties.comment,
47014 comment = _feature$properties$c === void 0 ? null : _feature$properties$c,
47015 objectId = _feature$properties.object_id,
47016 objectType = _feature$properties.object_type,
47017 schema = _feature$properties.schema,
47018 title = _feature$properties.title;
47019 var loc = feature.geometry.coordinates,
47020 _feature$properties$d = feature.properties.description,
47021 description = _feature$properties$d === void 0 ? '' : _feature$properties$d; // if there is a parent, save its error type e.g.:
47022 // Error 191 = "highway-highway"
47023 // Error 190 = "intersections without junctions" (parent)
47025 var issueTemplate = _krData.errorTypes[itemType];
47026 var parentIssueType = (Math.floor(itemType / 10) * 10).toString(); // try to handle error type directly, fallback to parent error type.
47028 var whichType = issueTemplate ? itemType : parentIssueType;
47029 var whichTemplate = _krData.errorTypes[whichType]; // Rewrite a few of the errors at this point..
47030 // This is done to make them easier to linkify and translate.
47032 switch (whichType) {
47034 description = "This feature has a FIXME tag: ".concat(description);
47039 description = description.replace('A turn-', 'This turn-');
47047 description = "This turn-restriction~".concat(description);
47051 description = 'This highway is missing a maxspeed tag';
47057 description = "This feature~".concat(description);
47059 } // move markers slightly so it doesn't obscure the geometry,
47060 // then move markers away from other coincident markers
47063 var coincident = false;
47066 // first time, move marker up. after that, move marker right.
47067 var delta = coincident ? [0.00001, 0] : [0, 0.00001];
47068 loc = geoVecAdd(loc, delta);
47069 var bbox = geoExtent(loc).bbox();
47070 coincident = _cache$2.rtree.search(bbox).length;
47071 } while (coincident);
47073 var d = new QAItem(loc, _this, itemType, id, {
47075 description: description,
47076 whichType: whichType,
47077 parentIssueType: parentIssueType,
47078 severity: whichTemplate.severity || 'error',
47079 objectId: objectId,
47080 objectType: objectType,
47084 d.replacements = tokenReplacements(d);
47085 _cache$2.data[id] = d;
47087 _cache$2.rtree.insert(encodeIssueRtree$2(d));
47089 dispatch$7.call('loaded');
47090 })["catch"](function () {
47091 delete _cache$2.inflightTile[tile.id];
47092 _cache$2.loadedTile[tile.id] = true;
47096 postUpdate: function postUpdate(d, callback) {
47099 if (_cache$2.inflightPost[d.id]) {
47101 message: 'Error update already inflight',
47112 params.st = d.newStatus;
47115 if (d.newComment !== undefined) {
47116 params.co = d.newComment;
47117 } // NOTE: This throws a CORS err, but it seems successful.
47118 // We don't care too much about the response, so this is fine.
47121 var url = "".concat(_krUrlRoot, "/comment.php?") + utilQsString(params);
47122 var controller = new AbortController();
47123 _cache$2.inflightPost[d.id] = controller; // Since this is expected to throw an error just continue as if it worked
47124 // (worst case scenario the request truly fails and issue will show up if iD restarts)
47127 signal: controller.signal
47128 })["finally"](function () {
47129 delete _cache$2.inflightPost[d.id];
47131 if (d.newStatus === 'ignore') {
47132 // ignore permanently (false positive)
47133 _this2.removeItem(d);
47134 } else if (d.newStatus === 'ignore_t') {
47135 // ignore temporarily (error fixed)
47136 _this2.removeItem(d);
47138 _cache$2.closed["".concat(d.schema, ":").concat(d.id)] = true;
47140 d = _this2.replaceItem(d.update({
47141 comment: d.newComment,
47142 newComment: undefined,
47143 newState: undefined
47147 if (callback) callback(null, d);
47150 // Get all cached QAItems covering the viewport
47151 getItems: function getItems(projection) {
47152 var viewport = projection.clipExtent();
47153 var min = [viewport[0][0], viewport[1][1]];
47154 var max = [viewport[1][0], viewport[0][1]];
47155 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
47156 return _cache$2.rtree.search(bbox).map(function (d) {
47160 // Get a QAItem from cache
47161 // NOTE: Don't change method name until UI v3 is merged
47162 getError: function getError(id) {
47163 return _cache$2.data[id];
47165 // Replace a single QAItem in the cache
47166 replaceItem: function replaceItem(item) {
47167 if (!(item instanceof QAItem) || !item.id) return;
47168 _cache$2.data[item.id] = item;
47169 updateRtree$3(encodeIssueRtree$2(item), true); // true = replace
47173 // Remove a single QAItem from the cache
47174 removeItem: function removeItem(item) {
47175 if (!(item instanceof QAItem) || !item.id) return;
47176 delete _cache$2.data[item.id];
47177 updateRtree$3(encodeIssueRtree$2(item), false); // false = remove
47179 issueURL: function issueURL(item) {
47180 return "".concat(_krUrlRoot, "/report_map.php?schema=").concat(item.schema, "&error=").concat(item.id);
47182 // Get an array of issues closed during this session.
47183 // Used to populate `closed:keepright` changeset tag
47184 getClosedIDs: function getClosedIDs() {
47185 return Object.keys(_cache$2.closed).sort();
47189 var tiler$5 = utilTiler();
47190 var dispatch$6 = dispatch$8('loaded');
47191 var _tileZoom$2 = 14;
47192 var _impOsmUrls = {
47193 ow: 'https://grab.community.improve-osm.org/directionOfFlowService',
47194 mr: 'https://grab.community.improve-osm.org/missingGeoService',
47195 tr: 'https://grab.community.improve-osm.org/turnRestrictionService'
47197 var _impOsmData = {
47199 }; // This gets reassigned if reset
47203 function abortRequest$5(i) {
47204 Object.values(i).forEach(function (controller) {
47206 controller.abort();
47211 function abortUnwantedRequests$2(cache, tiles) {
47212 Object.keys(cache.inflightTile).forEach(function (k) {
47213 var wanted = tiles.find(function (tile) {
47214 return k === tile.id;
47218 abortRequest$5(cache.inflightTile[k]);
47219 delete cache.inflightTile[k];
47224 function encodeIssueRtree$1(d) {
47232 } // Replace or remove QAItem from rtree
47235 function updateRtree$2(item, replace) {
47236 _cache$1.rtree.remove(item, function (a, b) {
47237 return a.data.id === b.data.id;
47241 _cache$1.rtree.insert(item);
47245 function linkErrorObject(d) {
47246 return "<a class=\"error_object_link\">".concat(d, "</a>");
47249 function linkEntity(d) {
47250 return "<a class=\"error_entity_link\">".concat(d, "</a>");
47253 function pointAverage(points) {
47254 if (points.length) {
47255 var sum = points.reduce(function (acc, point) {
47256 return geoVecAdd(acc, [point.lon, point.lat]);
47258 return geoVecScale(sum, 1 / points.length);
47264 function relativeBearing(p1, p2) {
47265 var angle = Math.atan2(p2.lon - p1.lon, p2.lat - p1.lat);
47268 angle += 2 * Math.PI;
47269 } // Return degrees
47272 return angle * 180 / Math.PI;
47273 } // Assuming range [0,360)
47276 function cardinalDirection(bearing) {
47277 var dir = 45 * Math.round(bearing / 45);
47289 return _t("QA.improveOSM.directions.".concat(compass[dir]));
47290 } // Errors shouldn't obscure each other
47293 function preventCoincident$1(loc, bumpUp) {
47294 var coincident = false;
47297 // first time, move marker up. after that, move marker right.
47298 var delta = coincident ? [0.00001, 0] : bumpUp ? [0, 0.00001] : [0, 0];
47299 loc = geoVecAdd(loc, delta);
47300 var bbox = geoExtent(loc).bbox();
47301 coincident = _cache$1.rtree.search(bbox).length;
47302 } while (coincident);
47307 var serviceImproveOSM = {
47308 title: 'improveOSM',
47309 init: function init() {
47310 _mainFileFetcher.get('qa_data').then(function (d) {
47311 return _impOsmData = d.improveOSM;
47318 this.event = utilRebind(this, dispatch$6, 'on');
47320 reset: function reset() {
47322 Object.values(_cache$1.inflightTile).forEach(abortRequest$5);
47334 loadIssues: function loadIssues(projection) {
47340 zoom: '19' // Use a high zoom so that clusters aren't returned
47342 }; // determine the needed tiles to cover the view
47344 var tiles = tiler$5.zoomExtent([_tileZoom$2, _tileZoom$2]).getTiles(projection); // abort inflight requests that are no longer needed
47346 abortUnwantedRequests$2(_cache$1, tiles); // issue new requests..
47348 tiles.forEach(function (tile) {
47349 if (_cache$1.loadedTile[tile.id] || _cache$1.inflightTile[tile.id]) return;
47351 var _tile$extent$rectangl = tile.extent.rectangle(),
47352 _tile$extent$rectangl2 = _slicedToArray(_tile$extent$rectangl, 4),
47353 east = _tile$extent$rectangl2[0],
47354 north = _tile$extent$rectangl2[1],
47355 west = _tile$extent$rectangl2[2],
47356 south = _tile$extent$rectangl2[3];
47358 var params = Object.assign({}, options, {
47363 }); // 3 separate requests to store for each tile
47366 Object.keys(_impOsmUrls).forEach(function (k) {
47367 // We exclude WATER from missing geometry as it doesn't seem useful
47368 // We use most confident one-way and turn restrictions only, still have false positives
47369 var kParams = Object.assign({}, params, k === 'mr' ? {
47370 type: 'PARKING,ROAD,BOTH,PATH'
47372 confidenceLevel: 'C1'
47374 var url = "".concat(_impOsmUrls[k], "/search?") + utilQsString(kParams);
47375 var controller = new AbortController();
47376 requests[k] = controller;
47378 signal: controller.signal
47379 }).then(function (data) {
47380 delete _cache$1.inflightTile[tile.id][k];
47382 if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
47383 delete _cache$1.inflightTile[tile.id];
47384 _cache$1.loadedTile[tile.id] = true;
47385 } // Road segments at high zoom == oneways
47388 if (data.roadSegments) {
47389 data.roadSegments.forEach(function (feature) {
47390 // Position error at the approximate middle of the segment
47391 var points = feature.points,
47392 wayId = feature.wayId,
47393 fromNodeId = feature.fromNodeId,
47394 toNodeId = feature.toNodeId;
47395 var itemId = "".concat(wayId).concat(fromNodeId).concat(toNodeId);
47396 var mid = points.length / 2;
47397 var loc; // Even number of points, find midpoint of the middle two
47398 // Odd number of points, use position of very middle point
47400 if (mid % 1 === 0) {
47401 loc = pointAverage([points[mid - 1], points[mid]]);
47403 mid = points[Math.floor(mid)];
47404 loc = [mid.lon, mid.lat];
47405 } // One-ways can land on same segment in opposite direction
47408 loc = preventCoincident$1(loc, false);
47409 var d = new QAItem(loc, _this, k, itemId, {
47411 // used as a category
47413 // used to post changes
47415 fromNodeId: fromNodeId,
47420 }); // Variables used in the description
47423 percentage: feature.percentOfTrips,
47424 num_trips: feature.numberOfTrips,
47425 highway: linkErrorObject(_t('QA.keepRight.error_parts.highway')),
47426 from_node: linkEntity('n' + feature.fromNodeId),
47427 to_node: linkEntity('n' + feature.toNodeId)
47429 _cache$1.data[d.id] = d;
47431 _cache$1.rtree.insert(encodeIssueRtree$1(d));
47433 } // Tiles at high zoom == missing roads
47437 data.tiles.forEach(function (feature) {
47438 var type = feature.type,
47441 numberOfTrips = feature.numberOfTrips;
47442 var geoType = type.toLowerCase();
47443 var itemId = "".concat(geoType).concat(x).concat(y).concat(numberOfTrips); // Average of recorded points should land on the missing geometry
47444 // Missing geometry could happen to land on another error
47446 var loc = pointAverage(feature.points);
47447 loc = preventCoincident$1(loc, false);
47448 var d = new QAItem(loc, _this, "".concat(k, "-").concat(geoType), itemId, {
47456 num_trips: numberOfTrips,
47457 geometry_type: _t("QA.improveOSM.geometry_types.".concat(geoType))
47458 }; // -1 trips indicates data came from a 3rd party
47460 if (numberOfTrips === -1) {
47461 d.desc = _t('QA.improveOSM.error_types.mr.description_alt', d.replacements);
47464 _cache$1.data[d.id] = d;
47466 _cache$1.rtree.insert(encodeIssueRtree$1(d));
47468 } // Entities at high zoom == turn restrictions
47471 if (data.entities) {
47472 data.entities.forEach(function (feature) {
47473 var point = feature.point,
47475 segments = feature.segments,
47476 numberOfPasses = feature.numberOfPasses,
47477 turnType = feature.turnType;
47478 var itemId = "".concat(id.replace(/[,:+#]/g, '_')); // Turn restrictions could be missing at same junction
47479 // We also want to bump the error up so node is accessible
47481 var loc = preventCoincident$1([point.lon, point.lat], true); // Elements are presented in a strange way
47483 var ids = id.split(',');
47484 var from_way = ids[0];
47485 var via_node = ids[3];
47486 var to_way = ids[2].split(':')[1];
47487 var d = new QAItem(loc, _this, k, itemId, {
47490 objectId: via_node,
47492 }); // Travel direction along from_way clarifies the turn restriction
47494 var _segments$0$points = _slicedToArray(segments[0].points, 2),
47495 p1 = _segments$0$points[0],
47496 p2 = _segments$0$points[1];
47498 var dir_of_travel = cardinalDirection(relativeBearing(p1, p2)); // Variables used in the description
47501 num_passed: numberOfPasses,
47502 num_trips: segments[0].numberOfTrips,
47503 turn_restriction: turnType.toLowerCase(),
47504 from_way: linkEntity('w' + from_way),
47505 to_way: linkEntity('w' + to_way),
47506 travel_direction: dir_of_travel,
47507 junction: linkErrorObject(_t('QA.keepRight.error_parts.this_node'))
47509 _cache$1.data[d.id] = d;
47511 _cache$1.rtree.insert(encodeIssueRtree$1(d));
47513 dispatch$6.call('loaded');
47516 })["catch"](function () {
47517 delete _cache$1.inflightTile[tile.id][k];
47519 if (!Object.keys(_cache$1.inflightTile[tile.id]).length) {
47520 delete _cache$1.inflightTile[tile.id];
47521 _cache$1.loadedTile[tile.id] = true;
47525 _cache$1.inflightTile[tile.id] = requests;
47528 getComments: function getComments(item) {
47531 // If comments already retrieved no need to do so again
47532 if (item.comments) {
47533 return Promise.resolve(item);
47536 var key = item.issueKey;
47539 if (key === 'ow') {
47540 qParams = item.identifier;
47541 } else if (key === 'mr') {
47542 qParams.tileX = item.identifier.x;
47543 qParams.tileY = item.identifier.y;
47544 } else if (key === 'tr') {
47545 qParams.targetId = item.identifier;
47548 var url = "".concat(_impOsmUrls[key], "/retrieveComments?") + utilQsString(qParams);
47550 var cacheComments = function cacheComments(data) {
47551 // Assign directly for immediate use afterwards
47552 // comments are served newest to oldest
47553 item.comments = data.comments ? data.comments.reverse() : [];
47555 _this2.replaceItem(item);
47558 return d3_json(url).then(cacheComments).then(function () {
47562 postUpdate: function postUpdate(d, callback) {
47563 if (!serviceOsm.authenticated()) {
47564 // Username required in payload
47566 message: 'Not Authenticated',
47571 if (_cache$1.inflightPost[d.id]) {
47573 message: 'Error update already inflight',
47576 } // Payload can only be sent once username is established
47579 serviceOsm.userDetails(sendPayload.bind(this));
47581 function sendPayload(err, user) {
47585 return callback(err, d);
47588 var key = d.issueKey;
47589 var url = "".concat(_impOsmUrls[key], "/comment");
47591 username: user.display_name,
47592 targetIds: [d.identifier]
47596 payload.status = d.newStatus;
47597 payload.text = 'status changed';
47598 } // Comment take place of default text
47601 if (d.newComment) {
47602 payload.text = d.newComment;
47605 var controller = new AbortController();
47606 _cache$1.inflightPost[d.id] = controller;
47609 signal: controller.signal,
47610 body: JSON.stringify(payload)
47612 d3_json(url, options).then(function () {
47613 delete _cache$1.inflightPost[d.id]; // Just a comment, update error in cache
47615 if (!d.newStatus) {
47616 var now = new Date();
47617 var comments = d.comments ? d.comments : [];
47619 username: payload.username,
47620 text: payload.text,
47621 timestamp: now.getTime() / 1000
47624 _this3.replaceItem(d.update({
47625 comments: comments,
47626 newComment: undefined
47629 _this3.removeItem(d);
47631 if (d.newStatus === 'SOLVED') {
47632 // Keep track of the number of issues closed per type to tag the changeset
47633 if (!(d.issueKey in _cache$1.closed)) {
47634 _cache$1.closed[d.issueKey] = 0;
47637 _cache$1.closed[d.issueKey] += 1;
47641 if (callback) callback(null, d);
47642 })["catch"](function (err) {
47643 delete _cache$1.inflightPost[d.id];
47644 if (callback) callback(err.message);
47648 // Get all cached QAItems covering the viewport
47649 getItems: function getItems(projection) {
47650 var viewport = projection.clipExtent();
47651 var min = [viewport[0][0], viewport[1][1]];
47652 var max = [viewport[1][0], viewport[0][1]];
47653 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
47654 return _cache$1.rtree.search(bbox).map(function (d) {
47658 // Get a QAItem from cache
47659 // NOTE: Don't change method name until UI v3 is merged
47660 getError: function getError(id) {
47661 return _cache$1.data[id];
47663 // get the name of the icon to display for this item
47664 getIcon: function getIcon(itemType) {
47665 return _impOsmData.icons[itemType];
47667 // Replace a single QAItem in the cache
47668 replaceItem: function replaceItem(issue) {
47669 if (!(issue instanceof QAItem) || !issue.id) return;
47670 _cache$1.data[issue.id] = issue;
47671 updateRtree$2(encodeIssueRtree$1(issue), true); // true = replace
47675 // Remove a single QAItem from the cache
47676 removeItem: function removeItem(issue) {
47677 if (!(issue instanceof QAItem) || !issue.id) return;
47678 delete _cache$1.data[issue.id];
47679 updateRtree$2(encodeIssueRtree$1(issue), false); // false = remove
47681 // Used to populate `closed:improveosm:*` changeset tags
47682 getClosedCounts: function getClosedCounts() {
47683 return _cache$1.closed;
47687 var defaults$5 = {exports: {}};
47689 function getDefaults$1() {
47697 langPrefix: 'language-',
47705 smartypants: false,
47712 function changeDefaults$1(newDefaults) {
47713 defaults$5.exports.defaults = newDefaults;
47716 defaults$5.exports = {
47717 defaults: getDefaults$1(),
47718 getDefaults: getDefaults$1,
47719 changeDefaults: changeDefaults$1
47722 var escapeTest = /[&<>"']/;
47723 var escapeReplace = /[&<>"']/g;
47724 var escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
47725 var escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
47726 var escapeReplacements = {
47734 var getEscapeReplacement = function getEscapeReplacement(ch) {
47735 return escapeReplacements[ch];
47738 function escape$3(html, encode) {
47740 if (escapeTest.test(html)) {
47741 return html.replace(escapeReplace, getEscapeReplacement);
47744 if (escapeTestNoEncode.test(html)) {
47745 return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
47752 var unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
47754 function unescape$2(html) {
47755 // explicitly match decimal, hex, and named HTML entities
47756 return html.replace(unescapeTest, function (_, n) {
47757 n = n.toLowerCase();
47758 if (n === 'colon') return ':';
47760 if (n.charAt(0) === '#') {
47761 return n.charAt(1) === 'x' ? String.fromCharCode(parseInt(n.substring(2), 16)) : String.fromCharCode(+n.substring(1));
47768 var caret = /(^|[^\[])\^/g;
47770 function edit$1(regex, opt) {
47771 regex = regex.source || regex;
47774 replace: function replace(name, val) {
47775 val = val.source || val;
47776 val = val.replace(caret, '$1');
47777 regex = regex.replace(name, val);
47780 getRegex: function getRegex() {
47781 return new RegExp(regex, opt);
47787 var nonWordAndColonTest = /[^\w:]/g;
47788 var originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
47790 function cleanUrl$1(sanitize, base, href) {
47795 prot = decodeURIComponent(unescape$2(href)).replace(nonWordAndColonTest, '').toLowerCase();
47800 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
47805 if (base && !originIndependentUrl.test(href)) {
47806 href = resolveUrl$2(base, href);
47810 href = encodeURI(href).replace(/%25/g, '%');
47819 var justDomain = /^[^:]+:\/*[^/]*$/;
47820 var protocol = /^([^:]+:)[\s\S]*$/;
47821 var domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
47823 function resolveUrl$2(base, href) {
47824 if (!baseUrls[' ' + base]) {
47825 // we can ignore everything in base after the last slash of its path component,
47826 // but we might need to add _that_
47827 // https://tools.ietf.org/html/rfc3986#section-3
47828 if (justDomain.test(base)) {
47829 baseUrls[' ' + base] = base + '/';
47831 baseUrls[' ' + base] = rtrim$1(base, '/', true);
47835 base = baseUrls[' ' + base];
47836 var relativeBase = base.indexOf(':') === -1;
47838 if (href.substring(0, 2) === '//') {
47839 if (relativeBase) {
47843 return base.replace(protocol, '$1') + href;
47844 } else if (href.charAt(0) === '/') {
47845 if (relativeBase) {
47849 return base.replace(domain, '$1') + href;
47851 return base + href;
47856 exec: function noopTest() {}
47859 function merge$2(obj) {
47864 for (; i < arguments.length; i++) {
47865 target = arguments[i];
47867 for (key in target) {
47868 if (Object.prototype.hasOwnProperty.call(target, key)) {
47869 obj[key] = target[key];
47877 function splitCells$1(tableRow, count) {
47878 // ensure that every cell-delimiting pipe has a space
47879 // before it to distinguish it from an escaped pipe
47880 var row = tableRow.replace(/\|/g, function (match, offset, str) {
47881 var escaped = false,
47884 while (--curr >= 0 && str[curr] === '\\') {
47885 escaped = !escaped;
47889 // odd number of slashes means | is escaped
47890 // so we leave it alone
47893 // add space before unescaped |
47897 cells = row.split(/ \|/);
47900 if (cells.length > count) {
47901 cells.splice(count);
47903 while (cells.length < count) {
47908 for (; i < cells.length; i++) {
47909 // leading or trailing whitespace is ignored per the gfm spec
47910 cells[i] = cells[i].trim().replace(/\\\|/g, '|');
47914 } // Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').
47915 // /c*$/ is vulnerable to REDOS.
47916 // invert: Remove suffix of non-c chars instead. Default falsey.
47919 function rtrim$1(str, c, invert) {
47920 var l = str.length;
47924 } // Length of suffix matching the invert condition.
47927 var suffLen = 0; // Step left until we fail to match the invert condition.
47929 while (suffLen < l) {
47930 var currChar = str.charAt(l - suffLen - 1);
47932 if (currChar === c && !invert) {
47934 } else if (currChar !== c && invert) {
47941 return str.substr(0, l - suffLen);
47944 function findClosingBracket$1(str, b) {
47945 if (str.indexOf(b[1]) === -1) {
47949 var l = str.length;
47953 for (; i < l; i++) {
47954 if (str[i] === '\\') {
47956 } else if (str[i] === b[0]) {
47958 } else if (str[i] === b[1]) {
47970 function checkSanitizeDeprecation$1(opt) {
47971 if (opt && opt.sanitize && !opt.silent) {
47972 console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
47974 } // copied from https://stackoverflow.com/a/5450113/806777
47977 function repeatString$1(pattern, count) {
47984 while (count > 1) {
47990 pattern += pattern;
47993 return result + pattern;
47998 unescape: unescape$2,
48000 cleanUrl: cleanUrl$1,
48001 resolveUrl: resolveUrl$2,
48002 noopTest: noopTest$1,
48004 splitCells: splitCells$1,
48006 findClosingBracket: findClosingBracket$1,
48007 checkSanitizeDeprecation: checkSanitizeDeprecation$1,
48008 repeatString: repeatString$1
48011 var defaults$4 = defaults$5.exports.defaults;
48012 var rtrim = helpers.rtrim,
48013 splitCells = helpers.splitCells,
48014 _escape = helpers.escape,
48015 findClosingBracket = helpers.findClosingBracket;
48017 function outputLink(cap, link, raw) {
48018 var href = link.href;
48019 var title = link.title ? _escape(link.title) : null;
48020 var text = cap[1].replace(/\\([\[\]])/g, '$1');
48022 if (cap[0].charAt(0) !== '!') {
48036 text: _escape(text)
48041 function indentCodeCompensation(raw, text) {
48042 var matchIndentToCode = raw.match(/^(\s+)(?:```)/);
48044 if (matchIndentToCode === null) {
48048 var indentToCode = matchIndentToCode[1];
48049 return text.split('\n').map(function (node) {
48050 var matchIndentInNode = node.match(/^\s+/);
48052 if (matchIndentInNode === null) {
48056 var _matchIndentInNode = _slicedToArray(matchIndentInNode, 1),
48057 indentInNode = _matchIndentInNode[0];
48059 if (indentInNode.length >= indentToCode.length) {
48060 return node.slice(indentToCode.length);
48071 var Tokenizer_1 = /*#__PURE__*/function () {
48072 function Tokenizer(options) {
48073 _classCallCheck$1(this, Tokenizer);
48075 this.options = options || defaults$4;
48078 _createClass$1(Tokenizer, [{
48080 value: function space(src) {
48081 var cap = this.rules.block.newline.exec(src);
48084 if (cap[0].length > 1) {
48098 value: function code(src) {
48099 var cap = this.rules.block.code.exec(src);
48102 var text = cap[0].replace(/^ {1,4}/gm, '');
48106 codeBlockStyle: 'indented',
48107 text: !this.options.pedantic ? rtrim(text, '\n') : text
48113 value: function fences(src) {
48114 var cap = this.rules.block.fences.exec(src);
48118 var text = indentCodeCompensation(raw, cap[3] || '');
48122 lang: cap[2] ? cap[2].trim() : cap[2],
48129 value: function heading(src) {
48130 var cap = this.rules.block.heading.exec(src);
48133 var text = cap[2].trim(); // remove trailing #s
48135 if (/#$/.test(text)) {
48136 var trimmed = rtrim(text, '#');
48138 if (this.options.pedantic) {
48139 text = trimmed.trim();
48140 } else if (!trimmed || / $/.test(trimmed)) {
48141 // CommonMark requires space before trailing #s
48142 text = trimmed.trim();
48149 depth: cap[1].length,
48156 value: function nptable(src) {
48157 var cap = this.rules.block.nptable.exec(src);
48162 header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
48163 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
48164 cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : [],
48168 if (item.header.length === item.align.length) {
48169 var l = item.align.length;
48172 for (i = 0; i < l; i++) {
48173 if (/^ *-+: *$/.test(item.align[i])) {
48174 item.align[i] = 'right';
48175 } else if (/^ *:-+: *$/.test(item.align[i])) {
48176 item.align[i] = 'center';
48177 } else if (/^ *:-+ *$/.test(item.align[i])) {
48178 item.align[i] = 'left';
48180 item.align[i] = null;
48184 l = item.cells.length;
48186 for (i = 0; i < l; i++) {
48187 item.cells[i] = splitCells(item.cells[i], item.header.length);
48196 value: function hr(src) {
48197 var cap = this.rules.block.hr.exec(src);
48208 value: function blockquote(src) {
48209 var cap = this.rules.block.blockquote.exec(src);
48212 var text = cap[0].replace(/^ *> ?/gm, '');
48214 type: 'blockquote',
48222 value: function list(src) {
48223 var cap = this.rules.block.list.exec(src);
48228 var isordered = bull.length > 1;
48232 ordered: isordered,
48233 start: isordered ? +bull.slice(0, -1) : '',
48236 }; // Get each top-level item.
48238 var itemMatch = cap[0].match(this.rules.block.item);
48249 var l = itemMatch.length;
48250 bcurr = this.rules.block.listItemStart.exec(itemMatch[0]);
48252 for (var i = 0; i < l; i++) {
48253 item = itemMatch[i];
48256 if (!this.options.pedantic) {
48257 // Determine if current item contains the end of the list
48258 endMatch = item.match(new RegExp('\\n\\s*\\n {0,' + (bcurr[0].length - 1) + '}\\S'));
48261 addBack = item.length - endMatch.index + itemMatch.slice(i + 1).join('\n').length;
48262 list.raw = list.raw.substring(0, list.raw.length - addBack);
48263 item = item.substring(0, endMatch.index);
48267 } // Determine whether the next list item belongs here.
48268 // Backpedal if it does not belong in this list.
48272 bnext = this.rules.block.listItemStart.exec(itemMatch[i + 1]);
48274 if (!this.options.pedantic ? bnext[1].length >= bcurr[0].length || bnext[1].length > 3 : bnext[1].length > bcurr[1].length) {
48275 // nested list or continuation
48276 itemMatch.splice(i, 2, itemMatch[i] + (!this.options.pedantic && bnext[1].length < bcurr[0].length && !itemMatch[i].match(/\n$/) ? '' : '\n') + itemMatch[i + 1]);
48280 } else if ( // different bullet style
48281 !this.options.pedantic || this.options.smartLists ? bnext[2][bnext[2].length - 1] !== bull[bull.length - 1] : isordered === (bnext[2].length === 1)) {
48282 addBack = itemMatch.slice(i + 1).join('\n').length;
48283 list.raw = list.raw.substring(0, list.raw.length - addBack);
48288 } // Remove the list item's bullet
48289 // so it is seen as the next token.
48292 space = item.length;
48293 item = item.replace(/^ *([*+-]|\d+[.)]) ?/, ''); // Outdent whatever the
48294 // list item contains. Hacky.
48296 if (~item.indexOf('\n ')) {
48297 space -= item.length;
48298 item = !this.options.pedantic ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '') : item.replace(/^ {1,4}/gm, '');
48299 } // trim item newlines at end
48302 item = rtrim(item, '\n');
48306 } // Determine whether item is loose or not.
48307 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
48308 // for discount behavior.
48311 loose = next || /\n\n(?!\s*$)/.test(raw);
48314 next = raw.slice(-2) === '\n\n';
48315 if (!loose) loose = next;
48320 } // Check for task list items
48323 if (this.options.gfm) {
48324 istask = /^\[[ xX]\] /.test(item);
48325 ischecked = undefined;
48328 ischecked = item[1] !== ' ';
48329 item = item.replace(/^\[[ xX]\] +/, '');
48337 checked: ischecked,
48348 value: function html(src) {
48349 var cap = this.rules.block.html.exec(src);
48353 type: this.options.sanitize ? 'paragraph' : 'html',
48355 pre: !this.options.sanitizer && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
48356 text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
48362 value: function def(src) {
48363 var cap = this.rules.block.def.exec(src);
48366 if (cap[3]) cap[3] = cap[3].substring(1, cap[3].length - 1);
48367 var tag = cap[1].toLowerCase().replace(/\s+/g, ' ');
48379 value: function table(src) {
48380 var cap = this.rules.block.table.exec(src);
48385 header: splitCells(cap[1].replace(/^ *| *\| *$/g, '')),
48386 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
48387 cells: cap[3] ? cap[3].replace(/\n$/, '').split('\n') : []
48390 if (item.header.length === item.align.length) {
48392 var l = item.align.length;
48395 for (i = 0; i < l; i++) {
48396 if (/^ *-+: *$/.test(item.align[i])) {
48397 item.align[i] = 'right';
48398 } else if (/^ *:-+: *$/.test(item.align[i])) {
48399 item.align[i] = 'center';
48400 } else if (/^ *:-+ *$/.test(item.align[i])) {
48401 item.align[i] = 'left';
48403 item.align[i] = null;
48407 l = item.cells.length;
48409 for (i = 0; i < l; i++) {
48410 item.cells[i] = splitCells(item.cells[i].replace(/^ *\| *| *\| *$/g, ''), item.header.length);
48419 value: function lheading(src) {
48420 var cap = this.rules.block.lheading.exec(src);
48426 depth: cap[2].charAt(0) === '=' ? 1 : 2,
48433 value: function paragraph(src) {
48434 var cap = this.rules.block.paragraph.exec(src);
48440 text: cap[1].charAt(cap[1].length - 1) === '\n' ? cap[1].slice(0, -1) : cap[1]
48446 value: function text(src) {
48447 var cap = this.rules.block.text.exec(src);
48459 value: function escape(src) {
48460 var cap = this.rules.inline.escape.exec(src);
48466 text: _escape(cap[1])
48472 value: function tag(src, inLink, inRawBlock) {
48473 var cap = this.rules.inline.tag.exec(src);
48476 if (!inLink && /^<a /i.test(cap[0])) {
48478 } else if (inLink && /^<\/a>/i.test(cap[0])) {
48482 if (!inRawBlock && /^<(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
48484 } else if (inRawBlock && /^<\/(pre|code|kbd|script)(\s|>)/i.test(cap[0])) {
48485 inRawBlock = false;
48489 type: this.options.sanitize ? 'text' : 'html',
48492 inRawBlock: inRawBlock,
48493 text: this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0]
48499 value: function link(src) {
48500 var cap = this.rules.inline.link.exec(src);
48503 var trimmedUrl = cap[2].trim();
48505 if (!this.options.pedantic && /^</.test(trimmedUrl)) {
48506 // commonmark requires matching angle brackets
48507 if (!/>$/.test(trimmedUrl)) {
48509 } // ending angle bracket cannot be escaped
48512 var rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\');
48514 if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {
48518 // find closing parenthesis
48519 var lastParenIndex = findClosingBracket(cap[2], '()');
48521 if (lastParenIndex > -1) {
48522 var start = cap[0].indexOf('!') === 0 ? 5 : 4;
48523 var linkLen = start + cap[1].length + lastParenIndex;
48524 cap[2] = cap[2].substring(0, lastParenIndex);
48525 cap[0] = cap[0].substring(0, linkLen).trim();
48533 if (this.options.pedantic) {
48534 // split pedantic href and title
48535 var link = /^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(href);
48542 title = cap[3] ? cap[3].slice(1, -1) : '';
48545 href = href.trim();
48547 if (/^</.test(href)) {
48548 if (this.options.pedantic && !/>$/.test(trimmedUrl)) {
48549 // pedantic allows starting angle bracket without ending angle bracket
48550 href = href.slice(1);
48552 href = href.slice(1, -1);
48556 return outputLink(cap, {
48557 href: href ? href.replace(this.rules.inline._escapes, '$1') : href,
48558 title: title ? title.replace(this.rules.inline._escapes, '$1') : title
48564 value: function reflink(src, links) {
48567 if ((cap = this.rules.inline.reflink.exec(src)) || (cap = this.rules.inline.nolink.exec(src))) {
48568 var link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
48569 link = links[link.toLowerCase()];
48571 if (!link || !link.href) {
48572 var text = cap[0].charAt(0);
48580 return outputLink(cap, link, cap[0]);
48585 value: function emStrong(src, maskedSrc) {
48586 var prevChar = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';
48587 var match = this.rules.inline.emStrong.lDelim.exec(src);
48588 if (!match) return; // _ can't be between two alphanumerics. \p{L}\p{N} includes non-english alphabet/numbers as well
48590 if (match[3] && prevChar.match(/(?:[0-9A-Za-z\xAA\xB2\xB3\xB5\xB9\xBA\xBC-\xBE\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0560-\u0588\u05D0-\u05EA\u05EF-\u05F2\u0620-\u064A\u0660-\u0669\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07C0-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u0860-\u086A\u08A0-\u08B4\u08B6-\u08C7\u0904-\u0939\u093D\u0950\u0958-\u0961\u0966-\u096F\u0971-\u0980\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09E6-\u09F1\u09F4-\u09F9\u09FC\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A66-\u0A6F\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0AE6-\u0AEF\u0AF9\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B66-\u0B6F\u0B71-\u0B77\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0BE6-\u0BF2\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C39\u0C3D\u0C58-\u0C5A\u0C60\u0C61\u0C66-\u0C6F\u0C78-\u0C7E\u0C80\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CE6-\u0CEF\u0CF1\u0CF2\u0D04-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D54-\u0D56\u0D58-\u0D61\u0D66-\u0D78\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0DE6-\u0DEF\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E50-\u0E59\u0E81\u0E82\u0E84\u0E86-\u0E8A\u0E8C-\u0EA3\u0EA5\u0EA7-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0ED0-\u0ED9\u0EDC-\u0EDF\u0F00\u0F20-\u0F33\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F-\u1049\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u1090-\u1099\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1369-\u137C\u1380-\u138F\u13A0-\u13F5\u13F8-\u13FD\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u16EE-\u16F8\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u17E0-\u17E9\u17F0-\u17F9\u1810-\u1819\u1820-\u1878\u1880-\u1884\u1887-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191E\u1946-\u196D\u1970-\u1974\u1980-\u19AB\u19B0-\u19C9\u19D0-\u19DA\u1A00-\u1A16\u1A20-\u1A54\u1A80-\u1A89\u1A90-\u1A99\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B50-\u1B59\u1B83-\u1BA0\u1BAE-\u1BE5\u1C00-\u1C23\u1C40-\u1C49\u1C4D-\u1C7D\u1C80-\u1C88\u1C90-\u1CBA\u1CBD-\u1CBF\u1CE9-\u1CEC\u1CEE-\u1CF3\u1CF5\u1CF6\u1CFA\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2070\u2071\u2074-\u2079\u207F-\u2089\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2150-\u2189\u2460-\u249B\u24EA-\u24FF\u2776-\u2793\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2CFD\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005-\u3007\u3021-\u3029\u3031-\u3035\u3038-\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312F\u3131-\u318E\u3192-\u3195\u31A0-\u31BF\u31F0-\u31FF\u3220-\u3229\u3248-\u324F\u3251-\u325F\u3280-\u3289\u32B1-\u32BF\u3400-\u4DBF\u4E00-\u9FFC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA62B\uA640-\uA66E\uA67F-\uA69D\uA6A0-\uA6EF\uA717-\uA71F\uA722-\uA788\uA78B-\uA7BF\uA7C2-\uA7CA\uA7F5-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA830-\uA835\uA840-\uA873\uA882-\uA8B3\uA8D0-\uA8D9\uA8F2-\uA8F7\uA8FB\uA8FD\uA8FE\uA900-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF-\uA9D9\uA9E0-\uA9E4\uA9E6-\uA9FE\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA50-\uAA59\uAA60-\uAA76\uAA7A\uAA7E-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uAB30-\uAB5A\uAB5C-\uAB69\uAB70-\uABE2\uABF0-\uABF9\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]|\uD800[\uDC00-\uDC0B\uDC0D-\uDC26\uDC28-\uDC3A\uDC3C\uDC3D\uDC3F-\uDC4D\uDC50-\uDC5D\uDC80-\uDCFA\uDD07-\uDD33\uDD40-\uDD78\uDD8A\uDD8B\uDE80-\uDE9C\uDEA0-\uDED0\uDEE1-\uDEFB\uDF00-\uDF23\uDF2D-\uDF4A\uDF50-\uDF75\uDF80-\uDF9D\uDFA0-\uDFC3\uDFC8-\uDFCF\uDFD1-\uDFD5]|\uD801[\uDC00-\uDC9D\uDCA0-\uDCA9\uDCB0-\uDCD3\uDCD8-\uDCFB\uDD00-\uDD27\uDD30-\uDD63\uDE00-\uDF36\uDF40-\uDF55\uDF60-\uDF67]|\uD802[\uDC00-\uDC05\uDC08\uDC0A-\uDC35\uDC37\uDC38\uDC3C\uDC3F-\uDC55\uDC58-\uDC76\uDC79-\uDC9E\uDCA7-\uDCAF\uDCE0-\uDCF2\uDCF4\uDCF5\uDCFB-\uDD1B\uDD20-\uDD39\uDD80-\uDDB7\uDDBC-\uDDCF\uDDD2-\uDE00\uDE10-\uDE13\uDE15-\uDE17\uDE19-\uDE35\uDE40-\uDE48\uDE60-\uDE7E\uDE80-\uDE9F\uDEC0-\uDEC7\uDEC9-\uDEE4\uDEEB-\uDEEF\uDF00-\uDF35\uDF40-\uDF55\uDF58-\uDF72\uDF78-\uDF91\uDFA9-\uDFAF]|\uD803[\uDC00-\uDC48\uDC80-\uDCB2\uDCC0-\uDCF2\uDCFA-\uDD23\uDD30-\uDD39\uDE60-\uDE7E\uDE80-\uDEA9\uDEB0\uDEB1\uDF00-\uDF27\uDF30-\uDF45\uDF51-\uDF54\uDFB0-\uDFCB\uDFE0-\uDFF6]|\uD804[\uDC03-\uDC37\uDC52-\uDC6F\uDC83-\uDCAF\uDCD0-\uDCE8\uDCF0-\uDCF9\uDD03-\uDD26\uDD36-\uDD3F\uDD44\uDD47\uDD50-\uDD72\uDD76\uDD83-\uDDB2\uDDC1-\uDDC4\uDDD0-\uDDDA\uDDDC\uDDE1-\uDDF4\uDE00-\uDE11\uDE13-\uDE2B\uDE80-\uDE86\uDE88\uDE8A-\uDE8D\uDE8F-\uDE9D\uDE9F-\uDEA8\uDEB0-\uDEDE\uDEF0-\uDEF9\uDF05-\uDF0C\uDF0F\uDF10\uDF13-\uDF28\uDF2A-\uDF30\uDF32\uDF33\uDF35-\uDF39\uDF3D\uDF50\uDF5D-\uDF61]|\uD805[\uDC00-\uDC34\uDC47-\uDC4A\uDC50-\uDC59\uDC5F-\uDC61\uDC80-\uDCAF\uDCC4\uDCC5\uDCC7\uDCD0-\uDCD9\uDD80-\uDDAE\uDDD8-\uDDDB\uDE00-\uDE2F\uDE44\uDE50-\uDE59\uDE80-\uDEAA\uDEB8\uDEC0-\uDEC9\uDF00-\uDF1A\uDF30-\uDF3B]|\uD806[\uDC00-\uDC2B\uDCA0-\uDCF2\uDCFF-\uDD06\uDD09\uDD0C-\uDD13\uDD15\uDD16\uDD18-\uDD2F\uDD3F\uDD41\uDD50-\uDD59\uDDA0-\uDDA7\uDDAA-\uDDD0\uDDE1\uDDE3\uDE00\uDE0B-\uDE32\uDE3A\uDE50\uDE5C-\uDE89\uDE9D\uDEC0-\uDEF8]|\uD807[\uDC00-\uDC08\uDC0A-\uDC2E\uDC40\uDC50-\uDC6C\uDC72-\uDC8F\uDD00-\uDD06\uDD08\uDD09\uDD0B-\uDD30\uDD46\uDD50-\uDD59\uDD60-\uDD65\uDD67\uDD68\uDD6A-\uDD89\uDD98\uDDA0-\uDDA9\uDEE0-\uDEF2\uDFB0\uDFC0-\uDFD4]|\uD808[\uDC00-\uDF99]|\uD809[\uDC00-\uDC6E\uDC80-\uDD43]|[\uD80C\uD81C-\uD820\uD822\uD840-\uD868\uD86A-\uD86C\uD86F-\uD872\uD874-\uD879\uD880-\uD883][\uDC00-\uDFFF]|\uD80D[\uDC00-\uDC2E]|\uD811[\uDC00-\uDE46]|\uD81A[\uDC00-\uDE38\uDE40-\uDE5E\uDE60-\uDE69\uDED0-\uDEED\uDF00-\uDF2F\uDF40-\uDF43\uDF50-\uDF59\uDF5B-\uDF61\uDF63-\uDF77\uDF7D-\uDF8F]|\uD81B[\uDE40-\uDE96\uDF00-\uDF4A\uDF50\uDF93-\uDF9F\uDFE0\uDFE1\uDFE3]|\uD821[\uDC00-\uDFF7]|\uD823[\uDC00-\uDCD5\uDD00-\uDD08]|\uD82C[\uDC00-\uDD1E\uDD50-\uDD52\uDD64-\uDD67\uDD70-\uDEFB]|\uD82F[\uDC00-\uDC6A\uDC70-\uDC7C\uDC80-\uDC88\uDC90-\uDC99]|\uD834[\uDEE0-\uDEF3\uDF60-\uDF78]|\uD835[\uDC00-\uDC54\uDC56-\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDEA5\uDEA8-\uDEC0\uDEC2-\uDEDA\uDEDC-\uDEFA\uDEFC-\uDF14\uDF16-\uDF34\uDF36-\uDF4E\uDF50-\uDF6E\uDF70-\uDF88\uDF8A-\uDFA8\uDFAA-\uDFC2\uDFC4-\uDFCB\uDFCE-\uDFFF]|\uD838[\uDD00-\uDD2C\uDD37-\uDD3D\uDD40-\uDD49\uDD4E\uDEC0-\uDEEB\uDEF0-\uDEF9]|\uD83A[\uDC00-\uDCC4\uDCC7-\uDCCF\uDD00-\uDD43\uDD4B\uDD50-\uDD59]|\uD83B[\uDC71-\uDCAB\uDCAD-\uDCAF\uDCB1-\uDCB4\uDD01-\uDD2D\uDD2F-\uDD3D\uDE00-\uDE03\uDE05-\uDE1F\uDE21\uDE22\uDE24\uDE27\uDE29-\uDE32\uDE34-\uDE37\uDE39\uDE3B\uDE42\uDE47\uDE49\uDE4B\uDE4D-\uDE4F\uDE51\uDE52\uDE54\uDE57\uDE59\uDE5B\uDE5D\uDE5F\uDE61\uDE62\uDE64\uDE67-\uDE6A\uDE6C-\uDE72\uDE74-\uDE77\uDE79-\uDE7C\uDE7E\uDE80-\uDE89\uDE8B-\uDE9B\uDEA1-\uDEA3\uDEA5-\uDEA9\uDEAB-\uDEBB]|\uD83C[\uDD00-\uDD0C]|\uD83E[\uDFF0-\uDFF9]|\uD869[\uDC00-\uDEDD\uDF00-\uDFFF]|\uD86D[\uDC00-\uDF34\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1D\uDC20-\uDFFF]|\uD873[\uDC00-\uDEA1\uDEB0-\uDFFF]|\uD87A[\uDC00-\uDFE0]|\uD87E[\uDC00-\uDE1D]|\uD884[\uDC00-\uDF4A])/)) return;
48591 var nextChar = match[1] || match[2] || '';
48593 if (!nextChar || nextChar && (prevChar === '' || this.rules.inline.punctuation.exec(prevChar))) {
48594 var lLength = match[0].length - 1;
48597 delimTotal = lLength,
48599 var endReg = match[0][0] === '*' ? this.rules.inline.emStrong.rDelimAst : this.rules.inline.emStrong.rDelimUnd;
48600 endReg.lastIndex = 0; // Clip maskedSrc to same section of string as src (move to lexer?)
48602 maskedSrc = maskedSrc.slice(-1 * src.length + lLength);
48604 while ((match = endReg.exec(maskedSrc)) != null) {
48605 rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];
48606 if (!rDelim) continue; // skip single * in __abc*abc__
48608 rLength = rDelim.length;
48610 if (match[3] || match[4]) {
48611 // found another Left Delim
48612 delimTotal += rLength;
48614 } else if (match[5] || match[6]) {
48615 // either Left or Right Delim
48616 if (lLength % 3 && !((lLength + rLength) % 3)) {
48617 midDelimTotal += rLength;
48618 continue; // CommonMark Emphasis Rules 9-10
48622 delimTotal -= rLength;
48623 if (delimTotal > 0) continue; // Haven't found enough closing delimiters
48624 // Remove extra characters. *a*** -> *a*
48626 rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal); // Create `em` if smallest delimiter has odd char count. *a***
48628 if (Math.min(lLength, rLength) % 2) {
48631 raw: src.slice(0, lLength + match.index + rLength + 1),
48632 text: src.slice(1, lLength + match.index + rLength)
48634 } // Create 'strong' if smallest delimiter has even char count. **a***
48639 raw: src.slice(0, lLength + match.index + rLength + 1),
48640 text: src.slice(2, lLength + match.index + rLength - 1)
48647 value: function codespan(src) {
48648 var cap = this.rules.inline.code.exec(src);
48651 var text = cap[2].replace(/\n/g, ' ');
48652 var hasNonSpaceChars = /[^ ]/.test(text);
48653 var hasSpaceCharsOnBothEnds = /^ /.test(text) && / $/.test(text);
48655 if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
48656 text = text.substring(1, text.length - 1);
48659 text = _escape(text, true);
48669 value: function br(src) {
48670 var cap = this.rules.inline.br.exec(src);
48681 value: function del(src) {
48682 var cap = this.rules.inline.del.exec(src);
48694 value: function autolink(src, mangle) {
48695 var cap = this.rules.inline.autolink.exec(src);
48700 if (cap[2] === '@') {
48701 text = _escape(this.options.mangle ? mangle(cap[1]) : cap[1]);
48702 href = 'mailto:' + text;
48704 text = _escape(cap[1]);
48723 value: function url(src, mangle) {
48726 if (cap = this.rules.inline.url.exec(src)) {
48729 if (cap[2] === '@') {
48730 text = _escape(this.options.mangle ? mangle(cap[0]) : cap[0]);
48731 href = 'mailto:' + text;
48733 // do extended autolink path validation
48737 prevCapZero = cap[0];
48738 cap[0] = this.rules.inline._backpedal.exec(cap[0])[0];
48739 } while (prevCapZero !== cap[0]);
48741 text = _escape(cap[0]);
48743 if (cap[1] === 'www.') {
48744 href = 'http://' + text;
48765 value: function inlineText(src, inRawBlock, smartypants) {
48766 var cap = this.rules.inline.text.exec(src);
48772 text = this.options.sanitize ? this.options.sanitizer ? this.options.sanitizer(cap[0]) : _escape(cap[0]) : cap[0];
48774 text = _escape(this.options.smartypants ? smartypants(cap[0]) : cap[0]);
48789 var noopTest = helpers.noopTest,
48790 edit = helpers.edit,
48791 merge$1 = helpers.merge;
48793 * Block-Level Grammar
48797 newline: /^(?: *(?:\n|$))+/,
48798 code: /^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,
48799 fences: /^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,
48800 hr: /^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,
48801 heading: /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,
48802 blockquote: /^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,
48803 list: /^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,
48804 html: '^ {0,3}(?:' // optional indentation
48805 + '<(script|pre|style)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)' // (1)
48806 + '|comment[^\\n]*(\\n+|$)' // (2)
48807 + '|<\\?[\\s\\S]*?(?:\\?>\\n*|$)' // (3)
48808 + '|<![A-Z][\\s\\S]*?(?:>\\n*|$)' // (4)
48809 + '|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)' // (5)
48810 + '|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (6)
48811 + '|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) open tag
48812 + '|</(?!script|pre|style)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)' // (7) closing tag
48814 def: /^ {0,3}\[(label)\]: *\n? *<?([^\s>]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,
48817 lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,
48818 // regex template, placeholders will be replaced according to different paragraph
48819 // interruption rules of commonmark and the original markdown spec:
48820 _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,
48823 block$1._label = /(?!\s*\])(?:\\[\[\]]|[^\[\]])+/;
48824 block$1._title = /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/;
48825 block$1.def = edit(block$1.def).replace('label', block$1._label).replace('title', block$1._title).getRegex();
48826 block$1.bullet = /(?:[*+-]|\d{1,9}[.)])/;
48827 block$1.item = /^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/;
48828 block$1.item = edit(block$1.item, 'gm').replace(/bull/g, block$1.bullet).getRegex();
48829 block$1.listItemStart = edit(/^( *)(bull) */).replace('bull', block$1.bullet).getRegex();
48830 block$1.list = edit(block$1.list).replace(/bull/g, block$1.bullet).replace('hr', '\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))').replace('def', '\\n+(?=' + block$1.def.source + ')').getRegex();
48831 block$1._tag = 'address|article|aside|base|basefont|blockquote|body|caption' + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption' + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe' + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option' + '|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr' + '|track|ul';
48832 block$1._comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
48833 block$1.html = edit(block$1.html, 'i').replace('comment', block$1._comment).replace('tag', block$1._tag).replace('attribute', / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
48834 block$1.paragraph = edit(block$1._paragraph).replace('hr', block$1.hr).replace('heading', ' {0,3}#{1,6} ').replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs
48835 .replace('blockquote', ' {0,3}>').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
48836 .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // pars can be interrupted by type (6) html blocks
48838 block$1.blockquote = edit(block$1.blockquote).replace('paragraph', block$1.paragraph).getRegex();
48840 * Normal Block Grammar
48843 block$1.normal = merge$1({}, block$1);
48845 * GFM Block Grammar
48848 block$1.gfm = merge$1({}, block$1.normal, {
48849 nptable: '^ *([^|\\n ].*\\|.*)\\n' // Header
48850 + ' {0,3}([-:]+ *\\|[-| :]*)' // Align
48851 + '(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)',
48853 table: '^ *\\|(.+)\\n' // Header
48854 + ' {0,3}\\|?( *[-:]+[-| :]*)' // Align
48855 + '(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)' // Cells
48858 block$1.gfm.nptable = edit(block$1.gfm.nptable).replace('hr', block$1.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
48859 .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
48861 block$1.gfm.table = edit(block$1.gfm.table).replace('hr', block$1.hr).replace('heading', ' {0,3}#{1,6} ').replace('blockquote', ' {0,3}>').replace('code', ' {4}[^\\n]').replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n').replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt
48862 .replace('html', '</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|!--)').replace('tag', block$1._tag) // tables can be interrupted by type (6) html blocks
48865 * Pedantic grammar (original John Gruber's loose markdown specification)
48868 block$1.pedantic = merge$1({}, block$1.normal, {
48869 html: edit('^ *(?:comment *(?:\\n|\\s*$)' + '|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)' // closed tag
48870 + '|<tag(?:"[^"]*"|\'[^\']*\'|\\s[^\'"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))').replace('comment', block$1._comment).replace(/tag/g, '(?!(?:' + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub' + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)' + '\\b)\\w+(?!:|[^\\w\\s@]*@)\\b').getRegex(),
48871 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,
48872 heading: /^(#{1,6})(.*)(?:\n+|$)/,
48874 // fences not supported
48875 paragraph: edit(block$1.normal._paragraph).replace('hr', block$1.hr).replace('heading', ' *#{1,6} *[^\n]').replace('lheading', block$1.lheading).replace('blockquote', ' {0,3}>').replace('|fences', '').replace('|list', '').replace('|html', '').getRegex()
48878 * Inline-Level Grammar
48882 escape: /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,
48883 autolink: /^<(scheme:[^\s\x00-\x1f<>]*|email)>/,
48885 tag: '^comment' + '|^</[a-zA-Z][\\w:-]*\\s*>' // self-closing tag
48886 + '|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>' // open tag
48887 + '|^<\\?[\\s\\S]*?\\?>' // processing instruction, e.g. <?php ?>
48888 + '|^<![a-zA-Z]+\\s[\\s\\S]*?>' // declaration, e.g. <!DOCTYPE html>
48889 + '|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>',
48891 link: /^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,
48892 reflink: /^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,
48893 nolink: /^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,
48894 reflinkSearch: 'reflink|nolink(?!\\()',
48896 lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
48897 // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
48898 // () Skip other delimiter (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
48899 rDelimAst: /\_\_[^_*]*?\*[^_*]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
48900 rDelimUnd: /\*\*[^_*]*?\_[^_*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
48903 code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
48904 br: /^( {2,}|\\)\n(?!\s*$)/,
48906 text: /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,
48907 punctuation: /^([\spunctuation])/
48908 }; // list of punctuation marks from CommonMark spec
48909 // without * and _ to handle the different emphasis markers * and _
48911 inline$1._punctuation = '!"#$%&\'()+\\-.,/:;<=>?@\\[\\]`^{|}~';
48912 inline$1.punctuation = edit(inline$1.punctuation).replace(/punctuation/g, inline$1._punctuation).getRegex(); // sequences em should skip over [title](link), `code`, <html>
48914 inline$1.blockSkip = /\[[^\]]*?\]\([^\)]*?\)|`[^`]*?`|<[^>]*?>/g;
48915 inline$1.escapedEmSt = /\\\*|\\_/g;
48916 inline$1._comment = edit(block$1._comment).replace('(?:-->|$)', '-->').getRegex();
48917 inline$1.emStrong.lDelim = edit(inline$1.emStrong.lDelim).replace(/punct/g, inline$1._punctuation).getRegex();
48918 inline$1.emStrong.rDelimAst = edit(inline$1.emStrong.rDelimAst, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
48919 inline$1.emStrong.rDelimUnd = edit(inline$1.emStrong.rDelimUnd, 'g').replace(/punct/g, inline$1._punctuation).getRegex();
48920 inline$1._escapes = /\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g;
48921 inline$1._scheme = /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/;
48922 inline$1._email = /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/;
48923 inline$1.autolink = edit(inline$1.autolink).replace('scheme', inline$1._scheme).replace('email', inline$1._email).getRegex();
48924 inline$1._attribute = /\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/;
48925 inline$1.tag = edit(inline$1.tag).replace('comment', inline$1._comment).replace('attribute', inline$1._attribute).getRegex();
48926 inline$1._label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/;
48927 inline$1._href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/;
48928 inline$1._title = /"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/;
48929 inline$1.link = edit(inline$1.link).replace('label', inline$1._label).replace('href', inline$1._href).replace('title', inline$1._title).getRegex();
48930 inline$1.reflink = edit(inline$1.reflink).replace('label', inline$1._label).getRegex();
48931 inline$1.reflinkSearch = edit(inline$1.reflinkSearch, 'g').replace('reflink', inline$1.reflink).replace('nolink', inline$1.nolink).getRegex();
48933 * Normal Inline Grammar
48936 inline$1.normal = merge$1({}, inline$1);
48938 * Pedantic Inline Grammar
48941 inline$1.pedantic = merge$1({}, inline$1.normal, {
48944 middle: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
48945 endAst: /\*\*(?!\*)/g,
48950 middle: /^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,
48951 endAst: /\*(?!\*)/g,
48954 link: edit(/^!?\[(label)\]\((.*?)\)/).replace('label', inline$1._label).getRegex(),
48955 reflink: edit(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace('label', inline$1._label).getRegex()
48958 * GFM Inline Grammar
48961 inline$1.gfm = merge$1({}, inline$1.normal, {
48962 escape: edit(inline$1.escape).replace('])', '~|])').getRegex(),
48963 _extended_email: /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,
48964 url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
48965 _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
48966 del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
48967 text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
48969 inline$1.gfm.url = edit(inline$1.gfm.url, 'i').replace('email', inline$1.gfm._extended_email).getRegex();
48971 * GFM + Line Breaks Inline Grammar
48974 inline$1.breaks = merge$1({}, inline$1.gfm, {
48975 br: edit(inline$1.br).replace('{2,}', '*').getRegex(),
48976 text: edit(inline$1.gfm.text).replace('\\b_', '\\b_| {2,}\\n').replace(/\{2,\}/g, '*').getRegex()
48983 var Tokenizer$1 = Tokenizer_1;
48984 var defaults$3 = defaults$5.exports.defaults;
48985 var block = rules.block,
48986 inline = rules.inline;
48987 var repeatString = helpers.repeatString;
48989 * smartypants text replacement
48992 function smartypants(text) {
48993 return text // em-dashes
48994 .replace(/---/g, "\u2014") // en-dashes
48995 .replace(/--/g, "\u2013") // opening singles
48996 .replace(/(^|[-\u2014/(\[{"\s])'/g, "$1\u2018") // closing singles & apostrophes
48997 .replace(/'/g, "\u2019") // opening doubles
48998 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, "$1\u201C") // closing doubles
48999 .replace(/"/g, "\u201D") // ellipses
49000 .replace(/\.{3}/g, "\u2026");
49003 * mangle email addresses
49007 function mangle(text) {
49011 var l = text.length;
49013 for (i = 0; i < l; i++) {
49014 ch = text.charCodeAt(i);
49016 if (Math.random() > 0.5) {
49017 ch = 'x' + ch.toString(16);
49020 out += '&#' + ch + ';';
49030 var Lexer_1 = /*#__PURE__*/function () {
49031 function Lexer(options) {
49032 _classCallCheck$1(this, Lexer);
49035 this.tokens.links = Object.create(null);
49036 this.options = options || defaults$3;
49037 this.options.tokenizer = this.options.tokenizer || new Tokenizer$1();
49038 this.tokenizer = this.options.tokenizer;
49039 this.tokenizer.options = this.options;
49041 block: block.normal,
49042 inline: inline.normal
49045 if (this.options.pedantic) {
49046 rules.block = block.pedantic;
49047 rules.inline = inline.pedantic;
49048 } else if (this.options.gfm) {
49049 rules.block = block.gfm;
49051 if (this.options.breaks) {
49052 rules.inline = inline.breaks;
49054 rules.inline = inline.gfm;
49058 this.tokenizer.rules = rules;
49065 _createClass$1(Lexer, [{
49071 function lex(src) {
49072 src = src.replace(/\r\n|\r/g, '\n').replace(/\t/g, ' ');
49073 this.blockTokens(src, this.tokens, true);
49074 this.inline(this.tokens);
49075 return this.tokens;
49082 key: "blockTokens",
49083 value: function blockTokens(src) {
49084 var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49085 var top = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
49087 if (this.options.pedantic) {
49088 src = src.replace(/^ +$/gm, '');
49091 var token, i, l, lastToken;
49095 if (token = this.tokenizer.space(src)) {
49096 src = src.substring(token.raw.length);
49099 tokens.push(token);
49106 if (token = this.tokenizer.code(src)) {
49107 src = src.substring(token.raw.length);
49108 lastToken = tokens[tokens.length - 1]; // An indented code block cannot interrupt a paragraph.
49110 if (lastToken && lastToken.type === 'paragraph') {
49111 lastToken.raw += '\n' + token.raw;
49112 lastToken.text += '\n' + token.text;
49114 tokens.push(token);
49121 if (token = this.tokenizer.fences(src)) {
49122 src = src.substring(token.raw.length);
49123 tokens.push(token);
49128 if (token = this.tokenizer.heading(src)) {
49129 src = src.substring(token.raw.length);
49130 tokens.push(token);
49132 } // table no leading pipe (gfm)
49135 if (token = this.tokenizer.nptable(src)) {
49136 src = src.substring(token.raw.length);
49137 tokens.push(token);
49142 if (token = this.tokenizer.hr(src)) {
49143 src = src.substring(token.raw.length);
49144 tokens.push(token);
49149 if (token = this.tokenizer.blockquote(src)) {
49150 src = src.substring(token.raw.length);
49151 token.tokens = this.blockTokens(token.text, [], top);
49152 tokens.push(token);
49157 if (token = this.tokenizer.list(src)) {
49158 src = src.substring(token.raw.length);
49159 l = token.items.length;
49161 for (i = 0; i < l; i++) {
49162 token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
49165 tokens.push(token);
49170 if (token = this.tokenizer.html(src)) {
49171 src = src.substring(token.raw.length);
49172 tokens.push(token);
49177 if (top && (token = this.tokenizer.def(src))) {
49178 src = src.substring(token.raw.length);
49180 if (!this.tokens.links[token.tag]) {
49181 this.tokens.links[token.tag] = {
49191 if (token = this.tokenizer.table(src)) {
49192 src = src.substring(token.raw.length);
49193 tokens.push(token);
49198 if (token = this.tokenizer.lheading(src)) {
49199 src = src.substring(token.raw.length);
49200 tokens.push(token);
49202 } // top-level paragraph
49205 if (top && (token = this.tokenizer.paragraph(src))) {
49206 src = src.substring(token.raw.length);
49207 tokens.push(token);
49212 if (token = this.tokenizer.text(src)) {
49213 src = src.substring(token.raw.length);
49214 lastToken = tokens[tokens.length - 1];
49216 if (lastToken && lastToken.type === 'text') {
49217 lastToken.raw += '\n' + token.raw;
49218 lastToken.text += '\n' + token.text;
49220 tokens.push(token);
49227 var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
49229 if (this.options.silent) {
49230 console.error(errMsg);
49233 throw new Error(errMsg);
49242 value: function inline(tokens) {
49243 var i, j, k, l2, row, token;
49244 var l = tokens.length;
49246 for (i = 0; i < l; i++) {
49249 switch (token.type) {
49255 this.inlineTokens(token.text, token.tokens);
49266 l2 = token.header.length;
49268 for (j = 0; j < l2; j++) {
49269 token.tokens.header[j] = [];
49270 this.inlineTokens(token.header[j], token.tokens.header[j]);
49274 l2 = token.cells.length;
49276 for (j = 0; j < l2; j++) {
49277 row = token.cells[j];
49278 token.tokens.cells[j] = [];
49280 for (k = 0; k < row.length; k++) {
49281 token.tokens.cells[j][k] = [];
49282 this.inlineTokens(row[k], token.tokens.cells[j][k]);
49291 this.inline(token.tokens);
49297 l2 = token.items.length;
49299 for (j = 0; j < l2; j++) {
49300 this.inline(token.items[j].tokens);
49315 key: "inlineTokens",
49316 value: function inlineTokens(src) {
49317 var tokens = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
49318 var inLink = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
49319 var inRawBlock = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
49320 var token, lastToken; // String with links masked to avoid interference with em and strong
49322 var maskedSrc = src;
49324 var keepPrevChar, prevChar; // Mask out reflinks
49326 if (this.tokens.links) {
49327 var links = Object.keys(this.tokens.links);
49329 if (links.length > 0) {
49330 while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {
49331 if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {
49332 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);
49336 } // Mask out other blocks
49339 while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {
49340 maskedSrc = maskedSrc.slice(0, match.index) + '[' + repeatString('a', match[0].length - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);
49341 } // Mask out escaped em & strong delimiters
49344 while ((match = this.tokenizer.rules.inline.escapedEmSt.exec(maskedSrc)) != null) {
49345 maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.escapedEmSt.lastIndex);
49349 if (!keepPrevChar) {
49353 keepPrevChar = false; // escape
49355 if (token = this.tokenizer.escape(src)) {
49356 src = src.substring(token.raw.length);
49357 tokens.push(token);
49362 if (token = this.tokenizer.tag(src, inLink, inRawBlock)) {
49363 src = src.substring(token.raw.length);
49364 inLink = token.inLink;
49365 inRawBlock = token.inRawBlock;
49366 var _lastToken = tokens[tokens.length - 1];
49368 if (_lastToken && token.type === 'text' && _lastToken.type === 'text') {
49369 _lastToken.raw += token.raw;
49370 _lastToken.text += token.text;
49372 tokens.push(token);
49379 if (token = this.tokenizer.link(src)) {
49380 src = src.substring(token.raw.length);
49382 if (token.type === 'link') {
49383 token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
49386 tokens.push(token);
49388 } // reflink, nolink
49391 if (token = this.tokenizer.reflink(src, this.tokens.links)) {
49392 src = src.substring(token.raw.length);
49393 var _lastToken2 = tokens[tokens.length - 1];
49395 if (token.type === 'link') {
49396 token.tokens = this.inlineTokens(token.text, [], true, inRawBlock);
49397 tokens.push(token);
49398 } else if (_lastToken2 && token.type === 'text' && _lastToken2.type === 'text') {
49399 _lastToken2.raw += token.raw;
49400 _lastToken2.text += token.text;
49402 tokens.push(token);
49409 if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {
49410 src = src.substring(token.raw.length);
49411 token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
49412 tokens.push(token);
49417 if (token = this.tokenizer.codespan(src)) {
49418 src = src.substring(token.raw.length);
49419 tokens.push(token);
49424 if (token = this.tokenizer.br(src)) {
49425 src = src.substring(token.raw.length);
49426 tokens.push(token);
49431 if (token = this.tokenizer.del(src)) {
49432 src = src.substring(token.raw.length);
49433 token.tokens = this.inlineTokens(token.text, [], inLink, inRawBlock);
49434 tokens.push(token);
49439 if (token = this.tokenizer.autolink(src, mangle)) {
49440 src = src.substring(token.raw.length);
49441 tokens.push(token);
49446 if (!inLink && (token = this.tokenizer.url(src, mangle))) {
49447 src = src.substring(token.raw.length);
49448 tokens.push(token);
49453 if (token = this.tokenizer.inlineText(src, inRawBlock, smartypants)) {
49454 src = src.substring(token.raw.length);
49456 if (token.raw.slice(-1) !== '_') {
49457 // Track prevChar before string of ____ started
49458 prevChar = token.raw.slice(-1);
49461 keepPrevChar = true;
49462 lastToken = tokens[tokens.length - 1];
49464 if (lastToken && lastToken.type === 'text') {
49465 lastToken.raw += token.raw;
49466 lastToken.text += token.text;
49468 tokens.push(token);
49475 var errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);
49477 if (this.options.silent) {
49478 console.error(errMsg);
49481 throw new Error(errMsg);
49490 get: function get() {
49497 * Static Lex Method
49502 value: function lex(src, options) {
49503 var lexer = new Lexer(options);
49504 return lexer.lex(src);
49507 * Static Lex Inline Method
49512 value: function lexInline(src, options) {
49513 var lexer = new Lexer(options);
49514 return lexer.inlineTokens(src);
49521 var defaults$2 = defaults$5.exports.defaults;
49522 var cleanUrl = helpers.cleanUrl,
49523 escape$2 = helpers.escape;
49528 var Renderer_1 = /*#__PURE__*/function () {
49529 function Renderer(options) {
49530 _classCallCheck$1(this, Renderer);
49532 this.options = options || defaults$2;
49535 _createClass$1(Renderer, [{
49537 value: function code(_code, infostring, escaped) {
49538 var lang = (infostring || '').match(/\S*/)[0];
49540 if (this.options.highlight) {
49541 var out = this.options.highlight(_code, lang);
49543 if (out != null && out !== _code) {
49549 _code = _code.replace(/\n$/, '') + '\n';
49552 return '<pre><code>' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
49555 return '<pre><code class="' + this.options.langPrefix + escape$2(lang, true) + '">' + (escaped ? _code : escape$2(_code, true)) + '</code></pre>\n';
49559 value: function blockquote(quote) {
49560 return '<blockquote>\n' + quote + '</blockquote>\n';
49564 value: function html(_html) {
49569 value: function heading(text, level, raw, slugger) {
49570 if (this.options.headerIds) {
49571 return '<h' + level + ' id="' + this.options.headerPrefix + slugger.slug(raw) + '">' + text + '</h' + level + '>\n';
49575 return '<h' + level + '>' + text + '</h' + level + '>\n';
49579 value: function hr() {
49580 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
49584 value: function list(body, ordered, start) {
49585 var type = ordered ? 'ol' : 'ul',
49586 startatt = ordered && start !== 1 ? ' start="' + start + '"' : '';
49587 return '<' + type + startatt + '>\n' + body + '</' + type + '>\n';
49591 value: function listitem(text) {
49592 return '<li>' + text + '</li>\n';
49596 value: function checkbox(checked) {
49597 return '<input ' + (checked ? 'checked="" ' : '') + 'disabled="" type="checkbox"' + (this.options.xhtml ? ' /' : '') + '> ';
49601 value: function paragraph(text) {
49602 return '<p>' + text + '</p>\n';
49606 value: function table(header, body) {
49607 if (body) body = '<tbody>' + body + '</tbody>';
49608 return '<table>\n' + '<thead>\n' + header + '</thead>\n' + body + '</table>\n';
49612 value: function tablerow(content) {
49613 return '<tr>\n' + content + '</tr>\n';
49617 value: function tablecell(content, flags) {
49618 var type = flags.header ? 'th' : 'td';
49619 var tag = flags.align ? '<' + type + ' align="' + flags.align + '">' : '<' + type + '>';
49620 return tag + content + '</' + type + '>\n';
49621 } // span level renderer
49625 value: function strong(text) {
49626 return '<strong>' + text + '</strong>';
49630 value: function em(text) {
49631 return '<em>' + text + '</em>';
49635 value: function codespan(text) {
49636 return '<code>' + text + '</code>';
49640 value: function br() {
49641 return this.options.xhtml ? '<br/>' : '<br>';
49645 value: function del(text) {
49646 return '<del>' + text + '</del>';
49650 value: function link(href, title, text) {
49651 href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
49653 if (href === null) {
49657 var out = '<a href="' + escape$2(href) + '"';
49660 out += ' title="' + title + '"';
49663 out += '>' + text + '</a>';
49668 value: function image(href, title, text) {
49669 href = cleanUrl(this.options.sanitize, this.options.baseUrl, href);
49671 if (href === null) {
49675 var out = '<img src="' + href + '" alt="' + text + '"';
49678 out += ' title="' + title + '"';
49681 out += this.options.xhtml ? '/>' : '>';
49686 value: function text(_text) {
49694 var TextRenderer_1 = /*#__PURE__*/function () {
49695 function TextRenderer() {
49696 _classCallCheck$1(this, TextRenderer);
49699 _createClass$1(TextRenderer, [{
49701 value: // no need for block level renderers
49702 function strong(text) {
49707 value: function em(text) {
49712 value: function codespan(text) {
49717 value: function del(text) {
49722 value: function html(text) {
49727 value: function text(_text) {
49732 value: function link(href, title, text) {
49737 value: function image(href, title, text) {
49742 value: function br() {
49747 return TextRenderer;
49750 var Slugger_1 = /*#__PURE__*/function () {
49751 function Slugger() {
49752 _classCallCheck$1(this, Slugger);
49757 _createClass$1(Slugger, [{
49759 value: function serialize(value) {
49760 return value.toLowerCase().trim() // remove html tags
49761 .replace(/<[!\/a-z].*?>/ig, '') // remove unwanted chars
49762 .replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g, '').replace(/\s/g, '-');
49765 * Finds the next safe (unique) slug to use
49769 key: "getNextSafeSlug",
49770 value: function getNextSafeSlug(originalSlug, isDryRun) {
49771 var slug = originalSlug;
49772 var occurenceAccumulator = 0;
49774 if (this.seen.hasOwnProperty(slug)) {
49775 occurenceAccumulator = this.seen[originalSlug];
49778 occurenceAccumulator++;
49779 slug = originalSlug + '-' + occurenceAccumulator;
49780 } while (this.seen.hasOwnProperty(slug));
49784 this.seen[originalSlug] = occurenceAccumulator;
49785 this.seen[slug] = 0;
49791 * Convert string to unique id
49792 * @param {object} options
49793 * @param {boolean} options.dryrun Generates the next unique slug without updating the internal accumulator.
49798 value: function slug(value) {
49799 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
49800 var slug = this.serialize(value);
49801 return this.getNextSafeSlug(slug, options.dryrun);
49808 var Renderer$1 = Renderer_1;
49809 var TextRenderer$1 = TextRenderer_1;
49810 var Slugger$1 = Slugger_1;
49811 var defaults$1 = defaults$5.exports.defaults;
49812 var unescape$1 = helpers.unescape;
49814 * Parsing & Compiling
49817 var Parser_1 = /*#__PURE__*/function () {
49818 function Parser(options) {
49819 _classCallCheck$1(this, Parser);
49821 this.options = options || defaults$1;
49822 this.options.renderer = this.options.renderer || new Renderer$1();
49823 this.renderer = this.options.renderer;
49824 this.renderer.options = this.options;
49825 this.textRenderer = new TextRenderer$1();
49826 this.slugger = new Slugger$1();
49829 * Static Parse Method
49833 _createClass$1(Parser, [{
49839 function parse(tokens) {
49840 var top = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
49860 var l = tokens.length;
49862 for (i = 0; i < l; i++) {
49865 switch (token.type) {
49873 out += this.renderer.hr();
49879 out += this.renderer.heading(this.parseInline(token.tokens), token.depth, unescape$1(this.parseInline(token.tokens, this.textRenderer)), this.slugger);
49885 out += this.renderer.code(token.text, token.lang, token.escaped);
49891 header = ''; // header
49894 l2 = token.header.length;
49896 for (j = 0; j < l2; j++) {
49897 cell += this.renderer.tablecell(this.parseInline(token.tokens.header[j]), {
49899 align: token.align[j]
49903 header += this.renderer.tablerow(cell);
49905 l2 = token.cells.length;
49907 for (j = 0; j < l2; j++) {
49908 row = token.tokens.cells[j];
49912 for (k = 0; k < l3; k++) {
49913 cell += this.renderer.tablecell(this.parseInline(row[k]), {
49915 align: token.align[k]
49919 body += this.renderer.tablerow(cell);
49922 out += this.renderer.table(header, body);
49928 body = this.parse(token.tokens);
49929 out += this.renderer.blockquote(body);
49935 ordered = token.ordered;
49936 start = token.start;
49937 loose = token.loose;
49938 l2 = token.items.length;
49941 for (j = 0; j < l2; j++) {
49942 item = token.items[j];
49943 checked = item.checked;
49948 checkbox = this.renderer.checkbox(checked);
49951 if (item.tokens.length > 0 && item.tokens[0].type === 'text') {
49952 item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;
49954 if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {
49955 item.tokens[0].tokens[0].text = checkbox + ' ' + item.tokens[0].tokens[0].text;
49958 item.tokens.unshift({
49964 itemBody += checkbox;
49968 itemBody += this.parse(item.tokens, loose);
49969 body += this.renderer.listitem(itemBody, task, checked);
49972 out += this.renderer.list(body, ordered, start);
49978 // TODO parse inline content if parameter markdown=1
49979 out += this.renderer.html(token.text);
49985 out += this.renderer.paragraph(this.parseInline(token.tokens));
49991 body = token.tokens ? this.parseInline(token.tokens) : token.text;
49993 while (i + 1 < l && tokens[i + 1].type === 'text') {
49994 token = tokens[++i];
49995 body += '\n' + (token.tokens ? this.parseInline(token.tokens) : token.text);
49998 out += top ? this.renderer.paragraph(body) : body;
50004 var errMsg = 'Token with "' + token.type + '" type was not found.';
50006 if (this.options.silent) {
50007 console.error(errMsg);
50010 throw new Error(errMsg);
50019 * Parse Inline Tokens
50023 key: "parseInline",
50024 value: function parseInline(tokens, renderer) {
50025 renderer = renderer || this.renderer;
50029 var l = tokens.length;
50031 for (i = 0; i < l; i++) {
50034 switch (token.type) {
50037 out += renderer.text(token.text);
50043 out += renderer.html(token.text);
50049 out += renderer.link(token.href, token.title, this.parseInline(token.tokens, renderer));
50055 out += renderer.image(token.href, token.title, token.text);
50061 out += renderer.strong(this.parseInline(token.tokens, renderer));
50067 out += renderer.em(this.parseInline(token.tokens, renderer));
50073 out += renderer.codespan(token.text);
50079 out += renderer.br();
50085 out += renderer.del(this.parseInline(token.tokens, renderer));
50091 out += renderer.text(token.text);
50097 var errMsg = 'Token with "' + token.type + '" type was not found.';
50099 if (this.options.silent) {
50100 console.error(errMsg);
50103 throw new Error(errMsg);
50113 value: function parse(tokens, options) {
50114 var parser = new Parser(options);
50115 return parser.parse(tokens);
50118 * Static Parse Inline Method
50122 key: "parseInline",
50123 value: function parseInline(tokens, options) {
50124 var parser = new Parser(options);
50125 return parser.parseInline(tokens);
50132 var Lexer = Lexer_1;
50133 var Parser = Parser_1;
50134 var Tokenizer = Tokenizer_1;
50135 var Renderer = Renderer_1;
50136 var TextRenderer = TextRenderer_1;
50137 var Slugger = Slugger_1;
50138 var merge = helpers.merge,
50139 checkSanitizeDeprecation = helpers.checkSanitizeDeprecation,
50140 escape$1 = helpers.escape;
50141 var getDefaults = defaults$5.exports.getDefaults,
50142 changeDefaults = defaults$5.exports.changeDefaults,
50143 defaults = defaults$5.exports.defaults;
50148 function marked(src, opt, callback) {
50149 // throw error in case of non string input
50150 if (typeof src === 'undefined' || src === null) {
50151 throw new Error('marked(): input parameter is undefined or null');
50154 if (typeof src !== 'string') {
50155 throw new Error('marked(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
50158 if (typeof opt === 'function') {
50163 opt = merge({}, marked.defaults, opt || {});
50164 checkSanitizeDeprecation(opt);
50167 var highlight = opt.highlight;
50171 tokens = Lexer.lex(src, opt);
50173 return callback(e);
50176 var done = function done(err) {
50181 if (opt.walkTokens) {
50182 marked.walkTokens(tokens, opt.walkTokens);
50185 out = Parser.parse(tokens, opt);
50191 opt.highlight = highlight;
50192 return err ? callback(err) : callback(null, out);
50195 if (!highlight || highlight.length < 3) {
50199 delete opt.highlight;
50200 if (!tokens.length) return done();
50202 marked.walkTokens(tokens, function (token) {
50203 if (token.type === 'code') {
50205 setTimeout(function () {
50206 highlight(token.text, token.lang, function (err, code) {
50211 if (code != null && code !== token.text) {
50213 token.escaped = true;
50218 if (pending === 0) {
50226 if (pending === 0) {
50234 var _tokens = Lexer.lex(src, opt);
50236 if (opt.walkTokens) {
50237 marked.walkTokens(_tokens, opt.walkTokens);
50240 return Parser.parse(_tokens, opt);
50242 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
50245 return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
50256 marked.options = marked.setOptions = function (opt) {
50257 merge(marked.defaults, opt);
50258 changeDefaults(marked.defaults);
50262 marked.getDefaults = getDefaults;
50263 marked.defaults = defaults;
50268 marked.use = function (extension) {
50269 var opts = merge({}, extension);
50271 if (extension.renderer) {
50273 var renderer = marked.defaults.renderer || new Renderer();
50275 var _loop = function _loop(prop) {
50276 var prevRenderer = renderer[prop];
50278 renderer[prop] = function () {
50279 for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
50280 args[_key] = arguments[_key];
50283 var ret = extension.renderer[prop].apply(renderer, args);
50285 if (ret === false) {
50286 ret = prevRenderer.apply(renderer, args);
50293 for (var prop in extension.renderer) {
50297 opts.renderer = renderer;
50301 if (extension.tokenizer) {
50303 var tokenizer = marked.defaults.tokenizer || new Tokenizer();
50305 var _loop2 = function _loop2(prop) {
50306 var prevTokenizer = tokenizer[prop];
50308 tokenizer[prop] = function () {
50309 for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
50310 args[_key2] = arguments[_key2];
50313 var ret = extension.tokenizer[prop].apply(tokenizer, args);
50315 if (ret === false) {
50316 ret = prevTokenizer.apply(tokenizer, args);
50323 for (var prop in extension.tokenizer) {
50327 opts.tokenizer = tokenizer;
50331 if (extension.walkTokens) {
50332 var walkTokens = marked.defaults.walkTokens;
50334 opts.walkTokens = function (token) {
50335 extension.walkTokens(token);
50343 marked.setOptions(opts);
50346 * Run callback for every token
50350 marked.walkTokens = function (tokens, callback) {
50351 var _iterator = _createForOfIteratorHelper(tokens),
50355 for (_iterator.s(); !(_step = _iterator.n()).done;) {
50356 var token = _step.value;
50359 switch (token.type) {
50362 var _iterator2 = _createForOfIteratorHelper(token.tokens.header),
50366 for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
50367 var cell = _step2.value;
50368 marked.walkTokens(cell, callback);
50376 var _iterator3 = _createForOfIteratorHelper(token.tokens.cells),
50380 for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
50381 var row = _step3.value;
50383 var _iterator4 = _createForOfIteratorHelper(row),
50387 for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
50388 var _cell = _step4.value;
50389 marked.walkTokens(_cell, callback);
50408 marked.walkTokens(token.items, callback);
50414 if (token.tokens) {
50415 marked.walkTokens(token.tokens, callback);
50431 marked.parseInline = function (src, opt) {
50432 // throw error in case of non string input
50433 if (typeof src === 'undefined' || src === null) {
50434 throw new Error('marked.parseInline(): input parameter is undefined or null');
50437 if (typeof src !== 'string') {
50438 throw new Error('marked.parseInline(): input parameter is of type ' + Object.prototype.toString.call(src) + ', string expected');
50441 opt = merge({}, marked.defaults, opt || {});
50442 checkSanitizeDeprecation(opt);
50445 var tokens = Lexer.lexInline(src, opt);
50447 if (opt.walkTokens) {
50448 marked.walkTokens(tokens, opt.walkTokens);
50451 return Parser.parseInline(tokens, opt);
50453 e.message += '\nPlease report this to https://github.com/markedjs/marked.';
50456 return '<p>An error occurred:</p><pre>' + escape$1(e.message + '', true) + '</pre>';
50467 marked.Parser = Parser;
50468 marked.parser = Parser.parse;
50469 marked.Renderer = Renderer;
50470 marked.TextRenderer = TextRenderer;
50471 marked.Lexer = Lexer;
50472 marked.lexer = Lexer.lex;
50473 marked.Tokenizer = Tokenizer;
50474 marked.Slugger = Slugger;
50475 marked.parse = marked;
50476 var marked_1 = marked;
50478 var tiler$4 = utilTiler();
50479 var dispatch$5 = dispatch$8('loaded');
50480 var _tileZoom$1 = 14;
50481 var _osmoseUrlRoot = 'https://osmose.openstreetmap.fr/api/0.3';
50482 var _osmoseData = {
50485 }; // This gets reassigned if reset
50489 function abortRequest$4(controller) {
50491 controller.abort();
50495 function abortUnwantedRequests$1(cache, tiles) {
50496 Object.keys(cache.inflightTile).forEach(function (k) {
50497 var wanted = tiles.find(function (tile) {
50498 return k === tile.id;
50502 abortRequest$4(cache.inflightTile[k]);
50503 delete cache.inflightTile[k];
50508 function encodeIssueRtree(d) {
50516 } // Replace or remove QAItem from rtree
50519 function updateRtree$1(item, replace) {
50520 _cache.rtree.remove(item, function (a, b) {
50521 return a.data.id === b.data.id;
50525 _cache.rtree.insert(item);
50527 } // Issues shouldn't obscure each other
50530 function preventCoincident(loc) {
50531 var coincident = false;
50534 // first time, move marker up. after that, move marker right.
50535 var delta = coincident ? [0.00001, 0] : [0, 0.00001];
50536 loc = geoVecAdd(loc, delta);
50537 var bbox = geoExtent(loc).bbox();
50538 coincident = _cache.rtree.search(bbox).length;
50539 } while (coincident);
50544 var serviceOsmose = {
50546 init: function init() {
50547 _mainFileFetcher.get('qa_data').then(function (d) {
50548 _osmoseData = d.osmose;
50549 _osmoseData.items = Object.keys(d.osmose.icons).map(function (s) {
50550 return s.split('-')[0];
50551 }).reduce(function (unique, item) {
50552 return unique.indexOf(item) !== -1 ? unique : [].concat(_toConsumableArray(unique), [item]);
50560 this.event = utilRebind(this, dispatch$5, 'on');
50562 reset: function reset() {
50567 Object.values(_cache.inflightTile).forEach(abortRequest$4); // Strings and colors are static and should not be re-populated
50569 _strings = _cache.strings;
50570 _colors = _cache.colors;
50579 rtree: new RBush(),
50584 loadIssues: function loadIssues(projection) {
50588 // Tiles return a maximum # of issues
50589 // So we want to filter our request for only types iD supports
50590 item: _osmoseData.items
50591 }; // determine the needed tiles to cover the view
50593 var tiles = tiler$4.zoomExtent([_tileZoom$1, _tileZoom$1]).getTiles(projection); // abort inflight requests that are no longer needed
50595 abortUnwantedRequests$1(_cache, tiles); // issue new requests..
50597 tiles.forEach(function (tile) {
50598 if (_cache.loadedTile[tile.id] || _cache.inflightTile[tile.id]) return;
50600 var _tile$xyz = _slicedToArray(tile.xyz, 3),
50605 var url = "".concat(_osmoseUrlRoot, "/issues/").concat(z, "/").concat(x, "/").concat(y, ".json?") + utilQsString(params);
50606 var controller = new AbortController();
50607 _cache.inflightTile[tile.id] = controller;
50609 signal: controller.signal
50610 }).then(function (data) {
50611 delete _cache.inflightTile[tile.id];
50612 _cache.loadedTile[tile.id] = true;
50614 if (data.features) {
50615 data.features.forEach(function (issue) {
50616 var _issue$properties = issue.properties,
50617 item = _issue$properties.item,
50618 cl = _issue$properties["class"],
50619 id = _issue$properties.uuid;
50620 /* Osmose issues are uniquely identified by a unique
50621 `item` and `class` combination (both integer values) */
50623 var itemType = "".concat(item, "-").concat(cl); // Filter out unsupported issue types (some are too specific or advanced)
50625 if (itemType in _osmoseData.icons) {
50626 var loc = issue.geometry.coordinates; // lon, lat
50628 loc = preventCoincident(loc);
50629 var d = new QAItem(loc, _this, itemType, id, {
50631 }); // Setting elems here prevents UI detail requests
50633 if (item === 8300 || item === 8360) {
50637 _cache.data[d.id] = d;
50639 _cache.rtree.insert(encodeIssueRtree(d));
50644 dispatch$5.call('loaded');
50645 })["catch"](function () {
50646 delete _cache.inflightTile[tile.id];
50647 _cache.loadedTile[tile.id] = true;
50651 loadIssueDetail: function loadIssueDetail(issue) {
50654 // Issue details only need to be fetched once
50655 if (issue.elems !== undefined) {
50656 return Promise.resolve(issue);
50659 var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "?langs=").concat(_mainLocalizer.localeCode());
50661 var cacheDetails = function cacheDetails(data) {
50662 // Associated elements used for highlighting
50663 // Assign directly for immediate use in the callback
50664 issue.elems = data.elems.map(function (e) {
50665 return e.type.substring(0, 1) + e.id;
50666 }); // Some issues have instance specific detail in a subtitle
50668 issue.detail = data.subtitle ? marked_1(data.subtitle.auto) : '';
50670 _this2.replaceItem(issue);
50673 return d3_json(url).then(cacheDetails).then(function () {
50677 loadStrings: function loadStrings() {
50678 var locale = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _mainLocalizer.localeCode();
50679 var items = Object.keys(_osmoseData.icons);
50681 if (locale in _cache.strings && Object.keys(_cache.strings[locale]).length === items.length) {
50682 return Promise.resolve(_cache.strings[locale]);
50683 } // May be partially populated already if some requests were successful
50686 if (!(locale in _cache.strings)) {
50687 _cache.strings[locale] = {};
50688 } // Only need to cache strings for supported issue types
50689 // Using multiple individual item + class requests to reduce fetched data size
50692 var allRequests = items.map(function (itemType) {
50693 // No need to request data we already have
50694 if (itemType in _cache.strings[locale]) return null;
50696 var cacheData = function cacheData(data) {
50697 // Bunch of nested single value arrays of objects
50698 var _data$categories = _slicedToArray(data.categories, 1),
50699 _data$categories$ = _data$categories[0],
50700 cat = _data$categories$ === void 0 ? {
50702 } : _data$categories$;
50704 var _cat$items = _slicedToArray(cat.items, 1),
50705 _cat$items$ = _cat$items[0],
50706 item = _cat$items$ === void 0 ? {
50710 var _item$class = _slicedToArray(item["class"], 1),
50711 _item$class$ = _item$class[0],
50712 cl = _item$class$ === void 0 ? null : _item$class$; // If null default value is reached, data wasn't as expected (or was empty)
50716 /* eslint-disable no-console */
50717 console.log("Osmose strings request (".concat(itemType, ") had unexpected data"));
50718 /* eslint-enable no-console */
50721 } // Cache served item colors to automatically style issue markers later
50724 var itemInt = item.item,
50725 color = item.color;
50727 if (/^#[A-Fa-f0-9]{6}|[A-Fa-f0-9]{3}/.test(color)) {
50728 _cache.colors[itemInt] = color;
50729 } // Value of root key will be null if no string exists
50730 // If string exists, value is an object with key 'auto' for string
50733 var title = cl.title,
50734 detail = cl.detail,
50736 trap = cl.trap; // Osmose titles shouldn't contain markdown
50738 var issueStrings = {};
50739 if (title) issueStrings.title = title.auto;
50740 if (detail) issueStrings.detail = marked_1(detail.auto);
50741 if (trap) issueStrings.trap = marked_1(trap.auto);
50742 if (fix) issueStrings.fix = marked_1(fix.auto);
50743 _cache.strings[locale][itemType] = issueStrings;
50746 var _itemType$split = itemType.split('-'),
50747 _itemType$split2 = _slicedToArray(_itemType$split, 2),
50748 item = _itemType$split2[0],
50749 cl = _itemType$split2[1]; // Osmose API falls back to English strings where untranslated or if locale doesn't exist
50752 var url = "".concat(_osmoseUrlRoot, "/items/").concat(item, "/class/").concat(cl, "?langs=").concat(locale);
50753 return d3_json(url).then(cacheData);
50754 }).filter(Boolean);
50755 return Promise.all(allRequests).then(function () {
50756 return _cache.strings[locale];
50759 getStrings: function getStrings(itemType) {
50760 var locale = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _mainLocalizer.localeCode();
50761 // No need to fallback to English, Osmose API handles this for us
50762 return locale in _cache.strings ? _cache.strings[locale][itemType] : {};
50764 getColor: function getColor(itemType) {
50765 return itemType in _cache.colors ? _cache.colors[itemType] : '#FFFFFF';
50767 postUpdate: function postUpdate(issue, callback) {
50770 if (_cache.inflightPost[issue.id]) {
50772 message: 'Issue update already inflight',
50775 } // UI sets the status to either 'done' or 'false'
50778 var url = "".concat(_osmoseUrlRoot, "/issue/").concat(issue.id, "/").concat(issue.newStatus);
50779 var controller = new AbortController();
50781 var after = function after() {
50782 delete _cache.inflightPost[issue.id];
50784 _this3.removeItem(issue);
50786 if (issue.newStatus === 'done') {
50787 // Keep track of the number of issues closed per `item` to tag the changeset
50788 if (!(issue.item in _cache.closed)) {
50789 _cache.closed[issue.item] = 0;
50792 _cache.closed[issue.item] += 1;
50795 if (callback) callback(null, issue);
50798 _cache.inflightPost[issue.id] = controller;
50800 signal: controller.signal
50801 }).then(after)["catch"](function (err) {
50802 delete _cache.inflightPost[issue.id];
50803 if (callback) callback(err.message);
50806 // Get all cached QAItems covering the viewport
50807 getItems: function getItems(projection) {
50808 var viewport = projection.clipExtent();
50809 var min = [viewport[0][0], viewport[1][1]];
50810 var max = [viewport[1][0], viewport[0][1]];
50811 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
50812 return _cache.rtree.search(bbox).map(function (d) {
50816 // Get a QAItem from cache
50817 // NOTE: Don't change method name until UI v3 is merged
50818 getError: function getError(id) {
50819 return _cache.data[id];
50821 // get the name of the icon to display for this item
50822 getIcon: function getIcon(itemType) {
50823 return _osmoseData.icons[itemType];
50825 // Replace a single QAItem in the cache
50826 replaceItem: function replaceItem(item) {
50827 if (!(item instanceof QAItem) || !item.id) return;
50828 _cache.data[item.id] = item;
50829 updateRtree$1(encodeIssueRtree(item), true); // true = replace
50833 // Remove a single QAItem from the cache
50834 removeItem: function removeItem(item) {
50835 if (!(item instanceof QAItem) || !item.id) return;
50836 delete _cache.data[item.id];
50837 updateRtree$1(encodeIssueRtree(item), false); // false = remove
50839 // Used to populate `closed:osmose:*` changeset tags
50840 getClosedCounts: function getClosedCounts() {
50841 return _cache.closed;
50843 itemURL: function itemURL(item) {
50844 return "https://osmose.openstreetmap.fr/en/error/".concat(item.id);
50848 var ieee754$1 = {};
50850 /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
50852 ieee754$1.read = function (buffer, offset, isLE, mLen, nBytes) {
50854 var eLen = nBytes * 8 - mLen - 1;
50855 var eMax = (1 << eLen) - 1;
50856 var eBias = eMax >> 1;
50858 var i = isLE ? nBytes - 1 : 0;
50859 var d = isLE ? -1 : 1;
50860 var s = buffer[offset + i];
50862 e = s & (1 << -nBits) - 1;
50866 for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50868 m = e & (1 << -nBits) - 1;
50872 for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {}
50876 } else if (e === eMax) {
50877 return m ? NaN : (s ? -1 : 1) * Infinity;
50879 m = m + Math.pow(2, mLen);
50883 return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
50886 ieee754$1.write = function (buffer, value, offset, isLE, mLen, nBytes) {
50888 var eLen = nBytes * 8 - mLen - 1;
50889 var eMax = (1 << eLen) - 1;
50890 var eBias = eMax >> 1;
50891 var rt = mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0;
50892 var i = isLE ? 0 : nBytes - 1;
50893 var d = isLE ? 1 : -1;
50894 var s = value < 0 || value === 0 && 1 / value < 0 ? 1 : 0;
50895 value = Math.abs(value);
50897 if (isNaN(value) || value === Infinity) {
50898 m = isNaN(value) ? 1 : 0;
50901 e = Math.floor(Math.log(value) / Math.LN2);
50903 if (value * (c = Math.pow(2, -e)) < 1) {
50908 if (e + eBias >= 1) {
50911 value += rt * Math.pow(2, 1 - eBias);
50914 if (value * c >= 2) {
50919 if (e + eBias >= eMax) {
50922 } else if (e + eBias >= 1) {
50923 m = (value * c - 1) * Math.pow(2, mLen);
50926 m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
50931 for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {}
50936 for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {}
50938 buffer[offset + i - d] |= s * 128;
50942 var ieee754 = ieee754$1;
50944 function Pbf(buf) {
50945 this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf || 0);
50948 this.length = this.buf.length;
50951 Pbf.Varint = 0; // varint: int32, int64, uint32, uint64, sint32, sint64, bool, enum
50953 Pbf.Fixed64 = 1; // 64-bit: double, fixed64, sfixed64
50955 Pbf.Bytes = 2; // length-delimited: string, bytes, embedded messages, packed repeated fields
50957 Pbf.Fixed32 = 5; // 32-bit: float, fixed32, sfixed32
50959 var SHIFT_LEFT_32 = (1 << 16) * (1 << 16),
50960 SHIFT_RIGHT_32 = 1 / SHIFT_LEFT_32; // Threshold chosen based on both benchmarking and knowledge about browser string
50961 // data structures (which currently switch structure types at 12 bytes or more)
50963 var TEXT_DECODER_MIN_LENGTH = 12;
50964 var utf8TextDecoder = typeof TextDecoder === 'undefined' ? null : new TextDecoder('utf8');
50966 destroy: function destroy() {
50969 // === READING =================================================================
50970 readFields: function readFields(readField, result, end) {
50971 end = end || this.length;
50973 while (this.pos < end) {
50974 var val = this.readVarint(),
50976 startPos = this.pos;
50977 this.type = val & 0x7;
50978 readField(tag, result, this);
50979 if (this.pos === startPos) this.skip(val);
50984 readMessage: function readMessage(readField, result) {
50985 return this.readFields(readField, result, this.readVarint() + this.pos);
50987 readFixed32: function readFixed32() {
50988 var val = readUInt32(this.buf, this.pos);
50992 readSFixed32: function readSFixed32() {
50993 var val = readInt32(this.buf, this.pos);
50997 // 64-bit int handling is based on github.com/dpw/node-buffer-more-ints (MIT-licensed)
50998 readFixed64: function readFixed64() {
50999 var val = readUInt32(this.buf, this.pos) + readUInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
51003 readSFixed64: function readSFixed64() {
51004 var val = readUInt32(this.buf, this.pos) + readInt32(this.buf, this.pos + 4) * SHIFT_LEFT_32;
51008 readFloat: function readFloat() {
51009 var val = ieee754.read(this.buf, this.pos, true, 23, 4);
51013 readDouble: function readDouble() {
51014 var val = ieee754.read(this.buf, this.pos, true, 52, 8);
51018 readVarint: function readVarint(isSigned) {
51019 var buf = this.buf,
51022 b = buf[this.pos++];
51024 if (b < 0x80) return val;
51025 b = buf[this.pos++];
51026 val |= (b & 0x7f) << 7;
51027 if (b < 0x80) return val;
51028 b = buf[this.pos++];
51029 val |= (b & 0x7f) << 14;
51030 if (b < 0x80) return val;
51031 b = buf[this.pos++];
51032 val |= (b & 0x7f) << 21;
51033 if (b < 0x80) return val;
51035 val |= (b & 0x0f) << 28;
51036 return readVarintRemainder(val, isSigned, this);
51038 readVarint64: function readVarint64() {
51039 // for compatibility with v2.0.1
51040 return this.readVarint(true);
51042 readSVarint: function readSVarint() {
51043 var num = this.readVarint();
51044 return num % 2 === 1 ? (num + 1) / -2 : num / 2; // zigzag encoding
51046 readBoolean: function readBoolean() {
51047 return Boolean(this.readVarint());
51049 readString: function readString() {
51050 var end = this.readVarint() + this.pos;
51051 var pos = this.pos;
51054 if (end - pos >= TEXT_DECODER_MIN_LENGTH && utf8TextDecoder) {
51055 // longer strings are fast with the built-in browser TextDecoder API
51056 return readUtf8TextDecoder(this.buf, pos, end);
51057 } // short strings are fast with our custom implementation
51060 return readUtf8(this.buf, pos, end);
51062 readBytes: function readBytes() {
51063 var end = this.readVarint() + this.pos,
51064 buffer = this.buf.subarray(this.pos, end);
51068 // verbose for performance reasons; doesn't affect gzipped size
51069 readPackedVarint: function readPackedVarint(arr, isSigned) {
51070 if (this.type !== Pbf.Bytes) return arr.push(this.readVarint(isSigned));
51071 var end = readPackedEnd(this);
51074 while (this.pos < end) {
51075 arr.push(this.readVarint(isSigned));
51080 readPackedSVarint: function readPackedSVarint(arr) {
51081 if (this.type !== Pbf.Bytes) return arr.push(this.readSVarint());
51082 var end = readPackedEnd(this);
51085 while (this.pos < end) {
51086 arr.push(this.readSVarint());
51091 readPackedBoolean: function readPackedBoolean(arr) {
51092 if (this.type !== Pbf.Bytes) return arr.push(this.readBoolean());
51093 var end = readPackedEnd(this);
51096 while (this.pos < end) {
51097 arr.push(this.readBoolean());
51102 readPackedFloat: function readPackedFloat(arr) {
51103 if (this.type !== Pbf.Bytes) return arr.push(this.readFloat());
51104 var end = readPackedEnd(this);
51107 while (this.pos < end) {
51108 arr.push(this.readFloat());
51113 readPackedDouble: function readPackedDouble(arr) {
51114 if (this.type !== Pbf.Bytes) return arr.push(this.readDouble());
51115 var end = readPackedEnd(this);
51118 while (this.pos < end) {
51119 arr.push(this.readDouble());
51124 readPackedFixed32: function readPackedFixed32(arr) {
51125 if (this.type !== Pbf.Bytes) return arr.push(this.readFixed32());
51126 var end = readPackedEnd(this);
51129 while (this.pos < end) {
51130 arr.push(this.readFixed32());
51135 readPackedSFixed32: function readPackedSFixed32(arr) {
51136 if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed32());
51137 var end = readPackedEnd(this);
51140 while (this.pos < end) {
51141 arr.push(this.readSFixed32());
51146 readPackedFixed64: function readPackedFixed64(arr) {
51147 if (this.type !== Pbf.Bytes) return arr.push(this.readFixed64());
51148 var end = readPackedEnd(this);
51151 while (this.pos < end) {
51152 arr.push(this.readFixed64());
51157 readPackedSFixed64: function readPackedSFixed64(arr) {
51158 if (this.type !== Pbf.Bytes) return arr.push(this.readSFixed64());
51159 var end = readPackedEnd(this);
51162 while (this.pos < end) {
51163 arr.push(this.readSFixed64());
51168 skip: function skip(val) {
51169 var type = val & 0x7;
51170 if (type === Pbf.Varint) while (this.buf[this.pos++] > 0x7f) {} else if (type === Pbf.Bytes) this.pos = this.readVarint() + this.pos;else if (type === Pbf.Fixed32) this.pos += 4;else if (type === Pbf.Fixed64) this.pos += 8;else throw new Error('Unimplemented type: ' + type);
51172 // === WRITING =================================================================
51173 writeTag: function writeTag(tag, type) {
51174 this.writeVarint(tag << 3 | type);
51176 realloc: function realloc(min) {
51177 var length = this.length || 16;
51179 while (length < this.pos + min) {
51183 if (length !== this.length) {
51184 var buf = new Uint8Array(length);
51187 this.length = length;
51190 finish: function finish() {
51191 this.length = this.pos;
51193 return this.buf.subarray(0, this.length);
51195 writeFixed32: function writeFixed32(val) {
51197 writeInt32(this.buf, val, this.pos);
51200 writeSFixed32: function writeSFixed32(val) {
51202 writeInt32(this.buf, val, this.pos);
51205 writeFixed64: function writeFixed64(val) {
51207 writeInt32(this.buf, val & -1, this.pos);
51208 writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51211 writeSFixed64: function writeSFixed64(val) {
51213 writeInt32(this.buf, val & -1, this.pos);
51214 writeInt32(this.buf, Math.floor(val * SHIFT_RIGHT_32), this.pos + 4);
51217 writeVarint: function writeVarint(val) {
51220 if (val > 0xfffffff || val < 0) {
51221 writeBigVarint(val, this);
51226 this.buf[this.pos++] = val & 0x7f | (val > 0x7f ? 0x80 : 0);
51227 if (val <= 0x7f) return;
51228 this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51229 if (val <= 0x7f) return;
51230 this.buf[this.pos++] = (val >>>= 7) & 0x7f | (val > 0x7f ? 0x80 : 0);
51231 if (val <= 0x7f) return;
51232 this.buf[this.pos++] = val >>> 7 & 0x7f;
51234 writeSVarint: function writeSVarint(val) {
51235 this.writeVarint(val < 0 ? -val * 2 - 1 : val * 2);
51237 writeBoolean: function writeBoolean(val) {
51238 this.writeVarint(Boolean(val));
51240 writeString: function writeString(str) {
51242 this.realloc(str.length * 4);
51243 this.pos++; // reserve 1 byte for short string length
51245 var startPos = this.pos; // write the string directly to the buffer and see how much was written
51247 this.pos = writeUtf8(this.buf, str, this.pos);
51248 var len = this.pos - startPos;
51249 if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51251 this.pos = startPos - 1;
51252 this.writeVarint(len);
51255 writeFloat: function writeFloat(val) {
51257 ieee754.write(this.buf, val, this.pos, true, 23, 4);
51260 writeDouble: function writeDouble(val) {
51262 ieee754.write(this.buf, val, this.pos, true, 52, 8);
51265 writeBytes: function writeBytes(buffer) {
51266 var len = buffer.length;
51267 this.writeVarint(len);
51270 for (var i = 0; i < len; i++) {
51271 this.buf[this.pos++] = buffer[i];
51274 writeRawMessage: function writeRawMessage(fn, obj) {
51275 this.pos++; // reserve 1 byte for short message length
51276 // write the message directly to the buffer and see how much was written
51278 var startPos = this.pos;
51280 var len = this.pos - startPos;
51281 if (len >= 0x80) makeRoomForExtraLength(startPos, len, this); // finally, write the message length in the reserved place and restore the position
51283 this.pos = startPos - 1;
51284 this.writeVarint(len);
51287 writeMessage: function writeMessage(tag, fn, obj) {
51288 this.writeTag(tag, Pbf.Bytes);
51289 this.writeRawMessage(fn, obj);
51291 writePackedVarint: function writePackedVarint(tag, arr) {
51292 if (arr.length) this.writeMessage(tag, _writePackedVarint, arr);
51294 writePackedSVarint: function writePackedSVarint(tag, arr) {
51295 if (arr.length) this.writeMessage(tag, _writePackedSVarint, arr);
51297 writePackedBoolean: function writePackedBoolean(tag, arr) {
51298 if (arr.length) this.writeMessage(tag, _writePackedBoolean, arr);
51300 writePackedFloat: function writePackedFloat(tag, arr) {
51301 if (arr.length) this.writeMessage(tag, _writePackedFloat, arr);
51303 writePackedDouble: function writePackedDouble(tag, arr) {
51304 if (arr.length) this.writeMessage(tag, _writePackedDouble, arr);
51306 writePackedFixed32: function writePackedFixed32(tag, arr) {
51307 if (arr.length) this.writeMessage(tag, _writePackedFixed, arr);
51309 writePackedSFixed32: function writePackedSFixed32(tag, arr) {
51310 if (arr.length) this.writeMessage(tag, _writePackedSFixed, arr);
51312 writePackedFixed64: function writePackedFixed64(tag, arr) {
51313 if (arr.length) this.writeMessage(tag, _writePackedFixed2, arr);
51315 writePackedSFixed64: function writePackedSFixed64(tag, arr) {
51316 if (arr.length) this.writeMessage(tag, _writePackedSFixed2, arr);
51318 writeBytesField: function writeBytesField(tag, buffer) {
51319 this.writeTag(tag, Pbf.Bytes);
51320 this.writeBytes(buffer);
51322 writeFixed32Field: function writeFixed32Field(tag, val) {
51323 this.writeTag(tag, Pbf.Fixed32);
51324 this.writeFixed32(val);
51326 writeSFixed32Field: function writeSFixed32Field(tag, val) {
51327 this.writeTag(tag, Pbf.Fixed32);
51328 this.writeSFixed32(val);
51330 writeFixed64Field: function writeFixed64Field(tag, val) {
51331 this.writeTag(tag, Pbf.Fixed64);
51332 this.writeFixed64(val);
51334 writeSFixed64Field: function writeSFixed64Field(tag, val) {
51335 this.writeTag(tag, Pbf.Fixed64);
51336 this.writeSFixed64(val);
51338 writeVarintField: function writeVarintField(tag, val) {
51339 this.writeTag(tag, Pbf.Varint);
51340 this.writeVarint(val);
51342 writeSVarintField: function writeSVarintField(tag, val) {
51343 this.writeTag(tag, Pbf.Varint);
51344 this.writeSVarint(val);
51346 writeStringField: function writeStringField(tag, str) {
51347 this.writeTag(tag, Pbf.Bytes);
51348 this.writeString(str);
51350 writeFloatField: function writeFloatField(tag, val) {
51351 this.writeTag(tag, Pbf.Fixed32);
51352 this.writeFloat(val);
51354 writeDoubleField: function writeDoubleField(tag, val) {
51355 this.writeTag(tag, Pbf.Fixed64);
51356 this.writeDouble(val);
51358 writeBooleanField: function writeBooleanField(tag, val) {
51359 this.writeVarintField(tag, Boolean(val));
51363 function readVarintRemainder(l, s, p) {
51368 h = (b & 0x70) >> 4;
51369 if (b < 0x80) return toNum(l, h, s);
51371 h |= (b & 0x7f) << 3;
51372 if (b < 0x80) return toNum(l, h, s);
51374 h |= (b & 0x7f) << 10;
51375 if (b < 0x80) return toNum(l, h, s);
51377 h |= (b & 0x7f) << 17;
51378 if (b < 0x80) return toNum(l, h, s);
51380 h |= (b & 0x7f) << 24;
51381 if (b < 0x80) return toNum(l, h, s);
51383 h |= (b & 0x01) << 31;
51384 if (b < 0x80) return toNum(l, h, s);
51385 throw new Error('Expected varint not more than 10 bytes');
51388 function readPackedEnd(pbf) {
51389 return pbf.type === Pbf.Bytes ? pbf.readVarint() + pbf.pos : pbf.pos + 1;
51392 function toNum(low, high, isSigned) {
51394 return high * 0x100000000 + (low >>> 0);
51397 return (high >>> 0) * 0x100000000 + (low >>> 0);
51400 function writeBigVarint(val, pbf) {
51404 low = val % 0x100000000 | 0;
51405 high = val / 0x100000000 | 0;
51407 low = ~(-val % 0x100000000);
51408 high = ~(-val / 0x100000000);
51410 if (low ^ 0xffffffff) {
51414 high = high + 1 | 0;
51418 if (val >= 0x10000000000000000 || val < -0x10000000000000000) {
51419 throw new Error('Given varint doesn\'t fit into 10 bytes');
51423 writeBigVarintLow(low, high, pbf);
51424 writeBigVarintHigh(high, pbf);
51427 function writeBigVarintLow(low, high, pbf) {
51428 pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51430 pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51432 pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51434 pbf.buf[pbf.pos++] = low & 0x7f | 0x80;
51436 pbf.buf[pbf.pos] = low & 0x7f;
51439 function writeBigVarintHigh(high, pbf) {
51440 var lsb = (high & 0x07) << 4;
51441 pbf.buf[pbf.pos++] |= lsb | ((high >>>= 3) ? 0x80 : 0);
51443 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51445 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51447 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51449 pbf.buf[pbf.pos++] = high & 0x7f | ((high >>>= 7) ? 0x80 : 0);
51451 pbf.buf[pbf.pos++] = high & 0x7f;
51454 function makeRoomForExtraLength(startPos, len, pbf) {
51455 var extraLen = len <= 0x3fff ? 1 : len <= 0x1fffff ? 2 : len <= 0xfffffff ? 3 : Math.floor(Math.log(len) / (Math.LN2 * 7)); // if 1 byte isn't enough for encoding message length, shift the data to the right
51457 pbf.realloc(extraLen);
51459 for (var i = pbf.pos - 1; i >= startPos; i--) {
51460 pbf.buf[i + extraLen] = pbf.buf[i];
51464 function _writePackedVarint(arr, pbf) {
51465 for (var i = 0; i < arr.length; i++) {
51466 pbf.writeVarint(arr[i]);
51470 function _writePackedSVarint(arr, pbf) {
51471 for (var i = 0; i < arr.length; i++) {
51472 pbf.writeSVarint(arr[i]);
51476 function _writePackedFloat(arr, pbf) {
51477 for (var i = 0; i < arr.length; i++) {
51478 pbf.writeFloat(arr[i]);
51482 function _writePackedDouble(arr, pbf) {
51483 for (var i = 0; i < arr.length; i++) {
51484 pbf.writeDouble(arr[i]);
51488 function _writePackedBoolean(arr, pbf) {
51489 for (var i = 0; i < arr.length; i++) {
51490 pbf.writeBoolean(arr[i]);
51494 function _writePackedFixed(arr, pbf) {
51495 for (var i = 0; i < arr.length; i++) {
51496 pbf.writeFixed32(arr[i]);
51500 function _writePackedSFixed(arr, pbf) {
51501 for (var i = 0; i < arr.length; i++) {
51502 pbf.writeSFixed32(arr[i]);
51506 function _writePackedFixed2(arr, pbf) {
51507 for (var i = 0; i < arr.length; i++) {
51508 pbf.writeFixed64(arr[i]);
51512 function _writePackedSFixed2(arr, pbf) {
51513 for (var i = 0; i < arr.length; i++) {
51514 pbf.writeSFixed64(arr[i]);
51516 } // Buffer code below from https://github.com/feross/buffer, MIT-licensed
51519 function readUInt32(buf, pos) {
51520 return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + buf[pos + 3] * 0x1000000;
51523 function writeInt32(buf, val, pos) {
51525 buf[pos + 1] = val >>> 8;
51526 buf[pos + 2] = val >>> 16;
51527 buf[pos + 3] = val >>> 24;
51530 function readInt32(buf, pos) {
51531 return (buf[pos] | buf[pos + 1] << 8 | buf[pos + 2] << 16) + (buf[pos + 3] << 24);
51534 function readUtf8(buf, pos, end) {
51540 var c = null; // codepoint
51542 var bytesPerSequence = b0 > 0xEF ? 4 : b0 > 0xDF ? 3 : b0 > 0xBF ? 2 : 1;
51543 if (i + bytesPerSequence > end) break;
51546 if (bytesPerSequence === 1) {
51550 } else if (bytesPerSequence === 2) {
51553 if ((b1 & 0xC0) === 0x80) {
51554 c = (b0 & 0x1F) << 0x6 | b1 & 0x3F;
51560 } else if (bytesPerSequence === 3) {
51564 if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80) {
51565 c = (b0 & 0xF) << 0xC | (b1 & 0x3F) << 0x6 | b2 & 0x3F;
51567 if (c <= 0x7FF || c >= 0xD800 && c <= 0xDFFF) {
51571 } else if (bytesPerSequence === 4) {
51576 if ((b1 & 0xC0) === 0x80 && (b2 & 0xC0) === 0x80 && (b3 & 0xC0) === 0x80) {
51577 c = (b0 & 0xF) << 0x12 | (b1 & 0x3F) << 0xC | (b2 & 0x3F) << 0x6 | b3 & 0x3F;
51579 if (c <= 0xFFFF || c >= 0x110000) {
51587 bytesPerSequence = 1;
51588 } else if (c > 0xFFFF) {
51590 str += String.fromCharCode(c >>> 10 & 0x3FF | 0xD800);
51591 c = 0xDC00 | c & 0x3FF;
51594 str += String.fromCharCode(c);
51595 i += bytesPerSequence;
51601 function readUtf8TextDecoder(buf, pos, end) {
51602 return utf8TextDecoder.decode(buf.subarray(pos, end));
51605 function writeUtf8(buf, str, pos) {
51606 for (var i = 0, c, lead; i < str.length; i++) {
51607 c = str.charCodeAt(i); // code point
51609 if (c > 0xD7FF && c < 0xE000) {
51618 c = lead - 0xD800 << 10 | c - 0xDC00 | 0x10000;
51622 if (c > 0xDBFF || i + 1 === str.length) {
51643 buf[pos++] = c >> 0x6 | 0xC0;
51646 buf[pos++] = c >> 0xC | 0xE0;
51648 buf[pos++] = c >> 0x12 | 0xF0;
51649 buf[pos++] = c >> 0xC & 0x3F | 0x80;
51652 buf[pos++] = c >> 0x6 & 0x3F | 0x80;
51655 buf[pos++] = c & 0x3F | 0x80;
51662 var vectorTile = {};
51664 var pointGeometry = Point$1;
51666 * A standalone point geometry with useful accessor, comparison, and
51667 * modification methods.
51670 * @param {Number} x the x-coordinate. this could be longitude or screen
51671 * pixels, or any other sort of unit.
51672 * @param {Number} y the y-coordinate. this could be latitude or screen
51673 * pixels, or any other sort of unit.
51675 * var point = new Point(-77, 38);
51678 function Point$1(x, y) {
51683 Point$1.prototype = {
51685 * Clone this point, returning a new point that can be modified
51686 * without affecting the old one.
51687 * @return {Point} the clone
51689 clone: function clone() {
51690 return new Point$1(this.x, this.y);
51694 * Add this point's x & y coordinates to another point,
51695 * yielding a new point.
51696 * @param {Point} p the other point
51697 * @return {Point} output point
51699 add: function add(p) {
51700 return this.clone()._add(p);
51704 * Subtract this point's x & y coordinates to from point,
51705 * yielding a new point.
51706 * @param {Point} p the other point
51707 * @return {Point} output point
51709 sub: function sub(p) {
51710 return this.clone()._sub(p);
51714 * Multiply this point's x & y coordinates by point,
51715 * yielding a new point.
51716 * @param {Point} p the other point
51717 * @return {Point} output point
51719 multByPoint: function multByPoint(p) {
51720 return this.clone()._multByPoint(p);
51724 * Divide this point's x & y coordinates by point,
51725 * yielding a new point.
51726 * @param {Point} p the other point
51727 * @return {Point} output point
51729 divByPoint: function divByPoint(p) {
51730 return this.clone()._divByPoint(p);
51734 * Multiply this point's x & y coordinates by a factor,
51735 * yielding a new point.
51736 * @param {Point} k factor
51737 * @return {Point} output point
51739 mult: function mult(k) {
51740 return this.clone()._mult(k);
51744 * Divide this point's x & y coordinates by a factor,
51745 * yielding a new point.
51746 * @param {Point} k factor
51747 * @return {Point} output point
51749 div: function div(k) {
51750 return this.clone()._div(k);
51754 * Rotate this point around the 0, 0 origin by an angle a,
51756 * @param {Number} a angle to rotate around, in radians
51757 * @return {Point} output point
51759 rotate: function rotate(a) {
51760 return this.clone()._rotate(a);
51764 * Rotate this point around p point by an angle a,
51766 * @param {Number} a angle to rotate around, in radians
51767 * @param {Point} p Point to rotate around
51768 * @return {Point} output point
51770 rotateAround: function rotateAround(a, p) {
51771 return this.clone()._rotateAround(a, p);
51775 * Multiply this point by a 4x1 transformation matrix
51776 * @param {Array<Number>} m transformation matrix
51777 * @return {Point} output point
51779 matMult: function matMult(m) {
51780 return this.clone()._matMult(m);
51784 * Calculate this point but as a unit vector from 0, 0, meaning
51785 * that the distance from the resulting point to the 0, 0
51786 * coordinate will be equal to 1 and the angle from the resulting
51787 * point to the 0, 0 coordinate will be the same as before.
51788 * @return {Point} unit vector point
51790 unit: function unit() {
51791 return this.clone()._unit();
51795 * Compute a perpendicular point, where the new y coordinate
51796 * is the old x coordinate and the new x coordinate is the old y
51797 * coordinate multiplied by -1
51798 * @return {Point} perpendicular point
51800 perp: function perp() {
51801 return this.clone()._perp();
51805 * Return a version of this point with the x & y coordinates
51806 * rounded to integers.
51807 * @return {Point} rounded point
51809 round: function round() {
51810 return this.clone()._round();
51814 * Return the magitude of this point: this is the Euclidean
51815 * distance from the 0, 0 coordinate to this point's x and y
51817 * @return {Number} magnitude
51819 mag: function mag() {
51820 return Math.sqrt(this.x * this.x + this.y * this.y);
51824 * Judge whether this point is equal to another point, returning
51826 * @param {Point} other the other point
51827 * @return {boolean} whether the points are equal
51829 equals: function equals(other) {
51830 return this.x === other.x && this.y === other.y;
51834 * Calculate the distance from this point to another point
51835 * @param {Point} p the other point
51836 * @return {Number} distance
51838 dist: function dist(p) {
51839 return Math.sqrt(this.distSqr(p));
51843 * Calculate the distance from this point to another point,
51844 * without the square root step. Useful if you're comparing
51845 * relative distances.
51846 * @param {Point} p the other point
51847 * @return {Number} distance
51849 distSqr: function distSqr(p) {
51850 var dx = p.x - this.x,
51852 return dx * dx + dy * dy;
51856 * Get the angle from the 0, 0 coordinate to this point, in radians
51858 * @return {Number} angle
51860 angle: function angle() {
51861 return Math.atan2(this.y, this.x);
51865 * Get the angle from this point to another point, in radians
51866 * @param {Point} b the other point
51867 * @return {Number} angle
51869 angleTo: function angleTo(b) {
51870 return Math.atan2(this.y - b.y, this.x - b.x);
51874 * Get the angle between this point and another point, in radians
51875 * @param {Point} b the other point
51876 * @return {Number} angle
51878 angleWith: function angleWith(b) {
51879 return this.angleWithSep(b.x, b.y);
51883 * Find the angle of the two vectors, solving the formula for
51884 * the cross product a x b = |a||b|sin(θ) for θ.
51885 * @param {Number} x the x-coordinate
51886 * @param {Number} y the y-coordinate
51887 * @return {Number} the angle in radians
51889 angleWithSep: function angleWithSep(x, y) {
51890 return Math.atan2(this.x * y - this.y * x, this.x * x + this.y * y);
51892 _matMult: function _matMult(m) {
51893 var x = m[0] * this.x + m[1] * this.y,
51894 y = m[2] * this.x + m[3] * this.y;
51899 _add: function _add(p) {
51904 _sub: function _sub(p) {
51909 _mult: function _mult(k) {
51914 _div: function _div(k) {
51919 _multByPoint: function _multByPoint(p) {
51924 _divByPoint: function _divByPoint(p) {
51929 _unit: function _unit() {
51930 this._div(this.mag());
51934 _perp: function _perp() {
51940 _rotate: function _rotate(angle) {
51941 var cos = Math.cos(angle),
51942 sin = Math.sin(angle),
51943 x = cos * this.x - sin * this.y,
51944 y = sin * this.x + cos * this.y;
51949 _rotateAround: function _rotateAround(angle, p) {
51950 var cos = Math.cos(angle),
51951 sin = Math.sin(angle),
51952 x = p.x + cos * (this.x - p.x) - sin * (this.y - p.y),
51953 y = p.y + sin * (this.x - p.x) + cos * (this.y - p.y);
51958 _round: function _round() {
51959 this.x = Math.round(this.x);
51960 this.y = Math.round(this.y);
51965 * Construct a point from an array if necessary, otherwise if the input
51966 * is already a Point, or an unknown type, return it unchanged
51967 * @param {Array<Number>|Point|*} a any kind of input value
51968 * @return {Point} constructed point, or passed-through value.
51971 * var point = Point.convert([0, 1]);
51972 * // is equivalent to
51973 * var point = new Point(0, 1);
51976 Point$1.convert = function (a) {
51977 if (a instanceof Point$1) {
51981 if (Array.isArray(a)) {
51982 return new Point$1(a[0], a[1]);
51988 var Point = pointGeometry;
51989 var vectortilefeature = VectorTileFeature$1;
51991 function VectorTileFeature$1(pbf, end, extent, keys, values) {
51993 this.properties = {};
51994 this.extent = extent;
51995 this.type = 0; // Private
51998 this._geometry = -1;
52000 this._values = values;
52001 pbf.readFields(readFeature, this, end);
52004 function readFeature(tag, feature, pbf) {
52005 if (tag == 1) feature.id = pbf.readVarint();else if (tag == 2) readTag(pbf, feature);else if (tag == 3) feature.type = pbf.readVarint();else if (tag == 4) feature._geometry = pbf.pos;
52008 function readTag(pbf, feature) {
52009 var end = pbf.readVarint() + pbf.pos;
52011 while (pbf.pos < end) {
52012 var key = feature._keys[pbf.readVarint()],
52013 value = feature._values[pbf.readVarint()];
52015 feature.properties[key] = value;
52019 VectorTileFeature$1.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
52021 VectorTileFeature$1.prototype.loadGeometry = function () {
52022 var pbf = this._pbf;
52023 pbf.pos = this._geometry;
52024 var end = pbf.readVarint() + pbf.pos,
52032 while (pbf.pos < end) {
52034 var cmdLen = pbf.readVarint();
52035 cmd = cmdLen & 0x7;
52036 length = cmdLen >> 3;
52041 if (cmd === 1 || cmd === 2) {
52042 x += pbf.readSVarint();
52043 y += pbf.readSVarint();
52047 if (line) lines.push(line);
52051 line.push(new Point(x, y));
52052 } else if (cmd === 7) {
52053 // Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
52055 line.push(line[0].clone()); // closePolygon
52058 throw new Error('unknown command ' + cmd);
52062 if (line) lines.push(line);
52066 VectorTileFeature$1.prototype.bbox = function () {
52067 var pbf = this._pbf;
52068 pbf.pos = this._geometry;
52069 var end = pbf.readVarint() + pbf.pos,
52079 while (pbf.pos < end) {
52081 var cmdLen = pbf.readVarint();
52082 cmd = cmdLen & 0x7;
52083 length = cmdLen >> 3;
52088 if (cmd === 1 || cmd === 2) {
52089 x += pbf.readSVarint();
52090 y += pbf.readSVarint();
52091 if (x < x1) x1 = x;
52092 if (x > x2) x2 = x;
52093 if (y < y1) y1 = y;
52094 if (y > y2) y2 = y;
52095 } else if (cmd !== 7) {
52096 throw new Error('unknown command ' + cmd);
52100 return [x1, y1, x2, y2];
52103 VectorTileFeature$1.prototype.toGeoJSON = function (x, y, z) {
52104 var size = this.extent * Math.pow(2, z),
52105 x0 = this.extent * x,
52106 y0 = this.extent * y,
52107 coords = this.loadGeometry(),
52108 type = VectorTileFeature$1.types[this.type],
52112 function project(line) {
52113 for (var j = 0; j < line.length; j++) {
52115 y2 = 180 - (p.y + y0) * 360 / size;
52116 line[j] = [(p.x + x0) * 360 / size - 180, 360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90];
52120 switch (this.type) {
52124 for (i = 0; i < coords.length; i++) {
52125 points[i] = coords[i][0];
52133 for (i = 0; i < coords.length; i++) {
52134 project(coords[i]);
52140 coords = classifyRings(coords);
52142 for (i = 0; i < coords.length; i++) {
52143 for (j = 0; j < coords[i].length; j++) {
52144 project(coords[i][j]);
52151 if (coords.length === 1) {
52152 coords = coords[0];
52154 type = 'Multi' + type;
52161 coordinates: coords
52163 properties: this.properties
52166 if ('id' in this) {
52167 result.id = this.id;
52171 }; // classifies an array of rings into polygons with outer rings and holes
52174 function classifyRings(rings) {
52175 var len = rings.length;
52176 if (len <= 1) return [rings];
52181 for (var i = 0; i < len; i++) {
52182 var area = signedArea(rings[i]);
52183 if (area === 0) continue;
52184 if (ccw === undefined) ccw = area < 0;
52186 if (ccw === area < 0) {
52187 if (polygon) polygons.push(polygon);
52188 polygon = [rings[i]];
52190 polygon.push(rings[i]);
52194 if (polygon) polygons.push(polygon);
52198 function signedArea(ring) {
52201 for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
52204 sum += (p2.x - p1.x) * (p1.y + p2.y);
52210 var VectorTileFeature = vectortilefeature;
52211 var vectortilelayer = VectorTileLayer$1;
52213 function VectorTileLayer$1(pbf, end) {
52217 this.extent = 4096;
52218 this.length = 0; // Private
52223 this._features = [];
52224 pbf.readFields(readLayer, this, end);
52225 this.length = this._features.length;
52228 function readLayer(tag, layer, pbf) {
52229 if (tag === 15) layer.version = pbf.readVarint();else if (tag === 1) layer.name = pbf.readString();else if (tag === 5) layer.extent = pbf.readVarint();else if (tag === 2) layer._features.push(pbf.pos);else if (tag === 3) layer._keys.push(pbf.readString());else if (tag === 4) layer._values.push(readValueMessage(pbf));
52232 function readValueMessage(pbf) {
52234 end = pbf.readVarint() + pbf.pos;
52236 while (pbf.pos < end) {
52237 var tag = pbf.readVarint() >> 3;
52238 value = tag === 1 ? pbf.readString() : tag === 2 ? pbf.readFloat() : tag === 3 ? pbf.readDouble() : tag === 4 ? pbf.readVarint64() : tag === 5 ? pbf.readVarint() : tag === 6 ? pbf.readSVarint() : tag === 7 ? pbf.readBoolean() : null;
52242 } // return feature `i` from this layer as a `VectorTileFeature`
52245 VectorTileLayer$1.prototype.feature = function (i) {
52246 if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
52247 this._pbf.pos = this._features[i];
52249 var end = this._pbf.readVarint() + this._pbf.pos;
52251 return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
52254 var VectorTileLayer = vectortilelayer;
52255 var vectortile = VectorTile$1;
52257 function VectorTile$1(pbf, end) {
52258 this.layers = pbf.readFields(readTile, {}, end);
52261 function readTile(tag, layers, pbf) {
52263 var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
52264 if (layer.length) layers[layer.name] = layer;
52268 var VectorTile = vectorTile.VectorTile = vectortile;
52269 vectorTile.VectorTileFeature = vectortilefeature;
52270 vectorTile.VectorTileLayer = vectortilelayer;
52272 var accessToken = 'MLY|4100327730013843|5bb78b81720791946a9a7b956c57b7cf';
52273 var apiUrl = 'https://graph.mapillary.com/';
52274 var baseTileUrl = 'https://tiles.mapillary.com/maps/vtp';
52275 var mapFeatureTileUrl = "".concat(baseTileUrl, "/mly_map_feature_point/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52276 var tileUrl = "".concat(baseTileUrl, "/mly1_public/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52277 var trafficSignTileUrl = "".concat(baseTileUrl, "/mly_map_feature_traffic_sign/2/{z}/{x}/{y}?access_token=").concat(accessToken);
52278 var viewercss = 'mapillary-js/mapillary.css';
52279 var viewerjs = 'mapillary-js/mapillary.js';
52280 var minZoom$1 = 14;
52281 var dispatch$4 = dispatch$8('change', 'loadedImages', 'loadedSigns', 'loadedMapFeatures', 'bearingChanged', 'imageChanged');
52283 var _loadViewerPromise$2;
52285 var _mlyActiveImage;
52289 var _mlyFallback = false;
52291 var _mlyHighlightedDetection;
52293 var _mlyShowFeatureDetections = false;
52294 var _mlyShowSignDetections = false;
52298 var _mlyViewerFilter = ['all']; // Load all data for the specified type from Mapillary vector tiles
52300 function loadTiles$2(which, url, maxZoom, projection) {
52301 var tiler = utilTiler().zoomExtent([minZoom$1, maxZoom]).skipNullIsland(true);
52302 var tiles = tiler.getTiles(projection);
52303 tiles.forEach(function (tile) {
52304 loadTile$1(which, url, tile);
52306 } // Load all data for the specified type from one vector tile
52309 function loadTile$1(which, url, tile) {
52310 var cache = _mlyCache.requests;
52311 var tileId = "".concat(tile.id, "-").concat(which);
52312 if (cache.loaded[tileId] || cache.inflight[tileId]) return;
52313 var controller = new AbortController();
52314 cache.inflight[tileId] = controller;
52315 var requestUrl = url.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]).replace('{z}', tile.xyz[2]);
52316 fetch(requestUrl, {
52317 signal: controller.signal
52318 }).then(function (response) {
52319 if (!response.ok) {
52320 throw new Error(response.status + ' ' + response.statusText);
52323 cache.loaded[tileId] = true;
52324 delete cache.inflight[tileId];
52325 return response.arrayBuffer();
52326 }).then(function (data) {
52328 throw new Error('No Data');
52331 loadTileDataToCache(data, tile, which);
52333 if (which === 'images') {
52334 dispatch$4.call('loadedImages');
52335 } else if (which === 'signs') {
52336 dispatch$4.call('loadedSigns');
52337 } else if (which === 'points') {
52338 dispatch$4.call('loadedMapFeatures');
52340 })["catch"](function () {
52341 cache.loaded[tileId] = true;
52342 delete cache.inflight[tileId];
52344 } // Load the data from the vector tile into cache
52347 function loadTileDataToCache(data, tile, which) {
52348 var vectorTile = new VectorTile(new pbf(data));
52349 var features, cache, layer, i, feature, loc, d;
52351 if (vectorTile.layers.hasOwnProperty('image')) {
52353 cache = _mlyCache.images;
52354 layer = vectorTile.layers.image;
52356 for (i = 0; i < layer.length; i++) {
52357 feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52358 loc = feature.geometry.coordinates;
52361 captured_at: feature.properties.captured_at,
52362 ca: feature.properties.compass_angle,
52363 id: feature.properties.id,
52364 is_pano: feature.properties.is_pano,
52365 sequence_id: feature.properties.sequence_id
52367 cache.forImageId[d.id] = d;
52378 cache.rtree.load(features);
52382 if (vectorTile.layers.hasOwnProperty('sequence')) {
52384 cache = _mlyCache.sequences;
52385 layer = vectorTile.layers.sequence;
52387 for (i = 0; i < layer.length; i++) {
52388 feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52390 if (cache.lineString[feature.properties.id]) {
52391 cache.lineString[feature.properties.id].push(feature);
52393 cache.lineString[feature.properties.id] = [feature];
52398 if (vectorTile.layers.hasOwnProperty('point')) {
52400 cache = _mlyCache[which];
52401 layer = vectorTile.layers.point;
52403 for (i = 0; i < layer.length; i++) {
52404 feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52405 loc = feature.geometry.coordinates;
52408 id: feature.properties.id,
52409 first_seen_at: feature.properties.first_seen_at,
52410 last_seen_at: feature.properties.last_seen_at,
52411 value: feature.properties.value
52423 cache.rtree.load(features);
52427 if (vectorTile.layers.hasOwnProperty('traffic_sign')) {
52429 cache = _mlyCache[which];
52430 layer = vectorTile.layers.traffic_sign;
52432 for (i = 0; i < layer.length; i++) {
52433 feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
52434 loc = feature.geometry.coordinates;
52437 id: feature.properties.id,
52438 first_seen_at: feature.properties.first_seen_at,
52439 last_seen_at: feature.properties.last_seen_at,
52440 value: feature.properties.value
52452 cache.rtree.load(features);
52455 } // Get data from the API
52458 function loadData(url) {
52459 return fetch(url).then(function (response) {
52460 if (!response.ok) {
52461 throw new Error(response.status + ' ' + response.statusText);
52464 return response.json();
52465 }).then(function (result) {
52470 return result.data || [];
52472 } // Partition viewport into higher zoom tiles
52475 function partitionViewport$2(projection) {
52476 var z = geoScaleToZoom(projection.scale());
52477 var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
52479 var tiler = utilTiler().zoomExtent([z2, z2]);
52480 return tiler.getTiles(projection).map(function (tile) {
52481 return tile.extent;
52483 } // Return no more than `limit` results per partition.
52486 function searchLimited$2(limit, projection, rtree) {
52487 limit = limit || 5;
52488 return partitionViewport$2(projection).reduce(function (result, extent) {
52489 var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
52492 return found.length ? result.concat(found) : result;
52496 var serviceMapillary = {
52497 // Initialize Mapillary
52498 init: function init() {
52503 this.event = utilRebind(this, dispatch$4, 'on');
52505 // Reset cache and state
52506 reset: function reset() {
52508 Object.values(_mlyCache.requests.inflight).forEach(function (request) {
52515 rtree: new RBush(),
52518 image_detections: {
52528 rtree: new RBush(),
52536 _mlyActiveImage = null;
52538 // Get visible images
52539 images: function images(projection) {
52541 return searchLimited$2(limit, projection, _mlyCache.images.rtree);
52543 // Get visible traffic signs
52544 signs: function signs(projection) {
52546 return searchLimited$2(limit, projection, _mlyCache.signs.rtree);
52548 // Get visible map (point) features
52549 mapFeatures: function mapFeatures(projection) {
52551 return searchLimited$2(limit, projection, _mlyCache.points.rtree);
52553 // Get cached image by id
52554 cachedImage: function cachedImage(imageId) {
52555 return _mlyCache.images.forImageId[imageId];
52557 // Get visible sequences
52558 sequences: function sequences(projection) {
52559 var viewport = projection.clipExtent();
52560 var min = [viewport[0][0], viewport[1][1]];
52561 var max = [viewport[1][0], viewport[0][1]];
52562 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
52563 var sequenceIds = {};
52564 var lineStrings = [];
52566 _mlyCache.images.rtree.search(bbox).forEach(function (d) {
52567 if (d.data.sequence_id) {
52568 sequenceIds[d.data.sequence_id] = true;
52572 Object.keys(sequenceIds).forEach(function (sequenceId) {
52573 if (_mlyCache.sequences.lineString[sequenceId]) {
52574 lineStrings = lineStrings.concat(_mlyCache.sequences.lineString[sequenceId]);
52577 return lineStrings;
52579 // Load images in the visible area
52580 loadImages: function loadImages(projection) {
52581 loadTiles$2('images', tileUrl, 14, projection);
52583 // Load traffic signs in the visible area
52584 loadSigns: function loadSigns(projection) {
52585 loadTiles$2('signs', trafficSignTileUrl, 14, projection);
52587 // Load map (point) features in the visible area
52588 loadMapFeatures: function loadMapFeatures(projection) {
52589 loadTiles$2('points', mapFeatureTileUrl, 14, projection);
52591 // Return a promise that resolves when the image viewer (Mapillary JS) library has finished loading
52592 ensureViewerLoaded: function ensureViewerLoaded(context) {
52593 if (_loadViewerPromise$2) return _loadViewerPromise$2; // add mly-wrapper
52595 var wrap = context.container().select('.photoviewer').selectAll('.mly-wrapper').data([0]);
52596 wrap.enter().append('div').attr('id', 'ideditor-mly').attr('class', 'photo-wrapper mly-wrapper').classed('hide', true);
52598 _loadViewerPromise$2 = new Promise(function (resolve, reject) {
52599 var loadedCount = 0;
52601 function loaded() {
52602 loadedCount += 1; // wait until both files are loaded
52604 if (loadedCount === 2) resolve();
52607 var head = select('head'); // load mapillary-viewercss
52609 head.selectAll('#ideditor-mapillary-viewercss').data([0]).enter().append('link').attr('id', 'ideditor-mapillary-viewercss').attr('rel', 'stylesheet').attr('crossorigin', 'anonymous').attr('href', context.asset(viewercss)).on('load.serviceMapillary', loaded).on('error.serviceMapillary', function () {
52611 }); // load mapillary-viewerjs
52613 head.selectAll('#ideditor-mapillary-viewerjs').data([0]).enter().append('script').attr('id', 'ideditor-mapillary-viewerjs').attr('crossorigin', 'anonymous').attr('src', context.asset(viewerjs)).on('load.serviceMapillary', loaded).on('error.serviceMapillary', function () {
52616 })["catch"](function () {
52617 _loadViewerPromise$2 = null;
52618 }).then(function () {
52619 that.initViewer(context);
52621 return _loadViewerPromise$2;
52623 // Load traffic sign image sprites
52624 loadSignResources: function loadSignResources(context) {
52625 context.ui().svgDefs.addSprites(['mapillary-sprite'], false
52626 /* don't override colors */
52630 // Load map (point) feature image sprites
52631 loadObjectResources: function loadObjectResources(context) {
52632 context.ui().svgDefs.addSprites(['mapillary-object-sprite'], false
52633 /* don't override colors */
52637 // Remove previous detections in image viewer
52638 resetTags: function resetTags() {
52639 if (_mlyViewer && !_mlyFallback) {
52640 _mlyViewer.getComponent('tag').removeAll();
52643 // Show map feature detections in image viewer
52644 showFeatureDetections: function showFeatureDetections(value) {
52645 _mlyShowFeatureDetections = value;
52647 if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
52651 // Show traffic sign detections in image viewer
52652 showSignDetections: function showSignDetections(value) {
52653 _mlyShowSignDetections = value;
52655 if (!_mlyShowFeatureDetections && !_mlyShowSignDetections) {
52659 // Apply filter to image viewer
52660 filterViewer: function filterViewer(context) {
52661 var showsPano = context.photos().showsPanoramic();
52662 var showsFlat = context.photos().showsFlat();
52663 var fromDate = context.photos().fromDate();
52664 var toDate = context.photos().toDate();
52665 var filter = ['all'];
52666 if (!showsPano) filter.push(['!=', 'cameraType', 'spherical']);
52667 if (!showsFlat && showsPano) filter.push(['==', 'pano', true]);
52670 filter.push(['>=', 'capturedAt', new Date(fromDate).getTime()]);
52674 filter.push(['>=', 'capturedAt', new Date(toDate).getTime()]);
52678 _mlyViewer.setFilter(filter);
52681 _mlyViewerFilter = filter;
52684 // Make the image viewer visible
52685 showViewer: function showViewer(context) {
52686 var wrap = context.container().select('.photoviewer').classed('hide', false);
52687 var isHidden = wrap.selectAll('.photo-wrapper.mly-wrapper.hide').size();
52689 if (isHidden && _mlyViewer) {
52690 wrap.selectAll('.photo-wrapper:not(.mly-wrapper)').classed('hide', true);
52691 wrap.selectAll('.photo-wrapper.mly-wrapper').classed('hide', false);
52693 _mlyViewer.resize();
52698 // Hide the image viewer and resets map markers
52699 hideViewer: function hideViewer(context) {
52700 _mlyActiveImage = null;
52702 if (!_mlyFallback && _mlyViewer) {
52703 _mlyViewer.getComponent('sequence').stop();
52706 var viewer = context.container().select('.photoviewer');
52707 if (!viewer.empty()) viewer.datum(null);
52708 viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
52709 this.updateUrlImage(null);
52710 dispatch$4.call('imageChanged');
52711 dispatch$4.call('loadedMapFeatures');
52712 dispatch$4.call('loadedSigns');
52713 return this.setStyles(context, null);
52715 // Update the URL with current image id
52716 updateUrlImage: function updateUrlImage(imageId) {
52717 if (!window.mocha) {
52718 var hash = utilStringQs(window.location.hash);
52721 hash.photo = 'mapillary/' + imageId;
52726 window.location.replace('#' + utilQsString(hash, true));
52729 // Highlight the detection in the viewer that is related to the clicked map feature
52730 highlightDetection: function highlightDetection(detection) {
52732 _mlyHighlightedDetection = detection.id;
52737 // Initialize image viewer (Mapillar JS)
52738 initViewer: function initViewer(context) {
52740 if (!window.mapillary) return;
52742 accessToken: accessToken,
52748 container: 'ideditor-mly'
52749 }; // Disable components requiring WebGL support
52751 if (!mapillary.isSupported() && mapillary.isFallbackSupported()) {
52752 _mlyFallback = true;
52763 navigation: true // fallback
52768 _mlyViewer = new mapillary.Viewer(opts);
52770 _mlyViewer.on('image', imageChanged);
52772 _mlyViewer.on('bearing', bearingChanged);
52774 if (_mlyViewerFilter) {
52775 _mlyViewer.setFilter(_mlyViewerFilter);
52776 } // Register viewer resize handler
52779 context.ui().photoviewer.on('resize.mapillary', function () {
52780 if (_mlyViewer) _mlyViewer.resize();
52781 }); // imageChanged: called after the viewer has changed images and is ready.
52783 function imageChanged(node) {
52785 var image = node.image;
52786 that.setActiveImage(image);
52787 that.setStyles(context, null);
52788 var loc = [image.originalLngLat.lng, image.originalLngLat.lat];
52789 context.map().centerEase(loc);
52790 that.updateUrlImage(image.id);
52792 if (_mlyShowFeatureDetections || _mlyShowSignDetections) {
52793 that.updateDetections(image.id, "".concat(apiUrl, "/").concat(image.id, "/detections?access_token=").concat(accessToken, "&fields=id,image,geometry,value"));
52796 dispatch$4.call('imageChanged');
52797 } // bearingChanged: called when the bearing changes in the image viewer.
52800 function bearingChanged(e) {
52801 dispatch$4.call('bearingChanged', undefined, e);
52804 // Move to an image
52805 selectImage: function selectImage(context, imageId) {
52806 if (_mlyViewer && imageId) {
52807 _mlyViewer.moveTo(imageId)["catch"](function (e) {
52808 console.error('mly3', e); // eslint-disable-line no-console
52814 // Return the currently displayed image
52815 getActiveImage: function getActiveImage() {
52816 return _mlyActiveImage;
52818 // Return a list of detection objects for the given id
52819 getDetections: function getDetections(id) {
52820 return loadData("".concat(apiUrl, "/").concat(id, "/detections?access_token=").concat(accessToken, "&fields=id,value,image"));
52822 // Set the currently visible image
52823 setActiveImage: function setActiveImage(image) {
52825 _mlyActiveImage = {
52826 ca: image.originalCompassAngle,
52828 loc: [image.originalLngLat.lng, image.originalLngLat.lat],
52829 is_pano: image.cameraType === 'spherical',
52830 sequence_id: image.sequenceId
52833 _mlyActiveImage = null;
52836 // Update the currently highlighted sequence and selected bubble.
52837 setStyles: function setStyles(context, hovered) {
52838 var hoveredImageId = hovered && hovered.id;
52839 var hoveredSequenceId = hovered && hovered.sequence_id;
52840 var selectedSequenceId = _mlyActiveImage && _mlyActiveImage.sequence_id;
52841 context.container().selectAll('.layer-mapillary .viewfield-group').classed('highlighted', function (d) {
52842 return d.sequence_id === selectedSequenceId || d.id === hoveredImageId;
52843 }).classed('hovered', function (d) {
52844 return d.id === hoveredImageId;
52846 context.container().selectAll('.layer-mapillary .sequence').classed('highlighted', function (d) {
52847 return d.properties.id === hoveredSequenceId;
52848 }).classed('currentView', function (d) {
52849 return d.properties.id === selectedSequenceId;
52853 // Get detections for the current image and shows them in the image viewer
52854 updateDetections: function updateDetections(imageId, url) {
52855 if (!_mlyViewer || _mlyFallback) return;
52856 if (!imageId) return;
52857 var cache = _mlyCache.image_detections;
52859 if (cache.forImageId[imageId]) {
52860 showDetections(_mlyCache.image_detections.forImageId[imageId]);
52862 loadData(url).then(function (detections) {
52863 detections.forEach(function (detection) {
52864 if (!cache.forImageId[imageId]) {
52865 cache.forImageId[imageId] = [];
52868 cache.forImageId[imageId].push({
52869 geometry: detection.geometry,
52872 value: detection.value
52875 showDetections(_mlyCache.image_detections.forImageId[imageId] || []);
52877 } // Create a tag for each detection and shows it in the image viewer
52880 function showDetections(detections) {
52881 var tagComponent = _mlyViewer.getComponent('tag');
52883 detections.forEach(function (data) {
52884 var tag = makeTag(data);
52887 tagComponent.add([tag]);
52890 } // Create a Mapillary JS tag object
52893 function makeTag(data) {
52894 var valueParts = data.value.split('--');
52895 if (!valueParts.length) return;
52898 var color = 0xffffff;
52900 if (_mlyHighlightedDetection === data.id) {
52902 text = valueParts[1];
52904 if (text === 'flat' || text === 'discrete' || text === 'sign') {
52905 text = valueParts[2];
52908 text = text.replace(/-/g, ' ');
52909 text = text.charAt(0).toUpperCase() + text.slice(1);
52910 _mlyHighlightedDetection = null;
52913 var decodedGeometry = window.atob(data.geometry);
52914 var uintArray = new Uint8Array(decodedGeometry.length);
52916 for (var i = 0; i < decodedGeometry.length; i++) {
52917 uintArray[i] = decodedGeometry.charCodeAt(i);
52920 var tile = new VectorTile(new pbf(uintArray.buffer));
52921 var layer = tile.layers['mpy-or'];
52922 var geometries = layer.feature(0).loadGeometry();
52923 var polygon = geometries.map(function (ring) {
52924 return ring.map(function (point) {
52925 return [point.x / layer.extent, point.y / layer.extent];
52928 tag = new mapillary.OutlineTag(data.id, new mapillary.PolygonGeometry(polygon[0]), {
52939 // Return the current cache
52940 cache: function cache() {
52945 function validationIssue(attrs) {
52946 this.type = attrs.type; // required - name of rule that created the issue (e.g. 'missing_tag')
52948 this.subtype = attrs.subtype; // optional - category of the issue within the type (e.g. 'relation_type' under 'missing_tag')
52950 this.severity = attrs.severity; // required - 'warning' or 'error'
52952 this.message = attrs.message; // required - function returning localized string
52954 this.reference = attrs.reference; // optional - function(selection) to render reference information
52956 this.entityIds = attrs.entityIds; // optional - array of IDs of entities involved in the issue
52958 this.loc = attrs.loc; // optional - [lon, lat] to zoom in on to see the issue
52960 this.data = attrs.data; // optional - object containing extra data for the fixes
52962 this.dynamicFixes = attrs.dynamicFixes; // optional - function(context) returning fixes
52964 this.hash = attrs.hash; // optional - string to further differentiate the issue
52966 this.id = generateID.apply(this); // generated - see below
52968 this.key = generateKey.apply(this); // generated - see below (call after generating this.id)
52970 this.autoFix = null; // generated - if autofix exists, will be set below
52971 // A unique, deterministic string hash.
52972 // Issues with identical id values are considered identical.
52974 function generateID() {
52975 var parts = [this.type];
52978 // subclasses can pass in their own differentiator
52979 parts.push(this.hash);
52982 if (this.subtype) {
52983 parts.push(this.subtype);
52984 } // include the entities this issue is for
52985 // (sort them so the id is deterministic)
52988 if (this.entityIds) {
52989 var entityKeys = this.entityIds.slice().sort();
52990 parts.push.apply(parts, entityKeys);
52993 return parts.join(':');
52994 } // An identifier suitable for use as the second argument to d3.selection#data().
52995 // (i.e. this should change whenever the data needs to be refreshed)
52998 function generateKey() {
52999 return this.id + ':' + Date.now().toString(); // include time of creation
53002 this.extent = function (resolver) {
53004 return geoExtent(this.loc);
53007 if (this.entityIds && this.entityIds.length) {
53008 return this.entityIds.reduce(function (extent, entityId) {
53009 return extent.extend(resolver.entity(entityId).extent(resolver));
53016 this.fixes = function (context) {
53017 var fixes = this.dynamicFixes ? this.dynamicFixes(context) : [];
53020 if (issue.severity === 'warning') {
53021 // allow ignoring any issue that's not an error
53022 fixes.push(new validationIssueFix({
53023 title: _t.html('issues.fix.ignore_issue.title'),
53024 icon: 'iD-icon-close',
53025 onClick: function onClick() {
53026 context.validator().ignoreIssue(this.issue.id);
53031 fixes.forEach(function (fix) {
53032 // the id doesn't matter as long as it's unique to this issue/fix
53033 fix.id = fix.title; // add a reference to the issue for use in actions
53037 if (fix.autoArgs) {
53038 issue.autoFix = fix;
53044 function validationIssueFix(attrs) {
53045 this.title = attrs.title; // Required
53047 this.onClick = attrs.onClick; // Optional - the function to run to apply the fix
53049 this.disabledReason = attrs.disabledReason; // Optional - a string explaining why the fix is unavailable, if any
53051 this.icon = attrs.icon; // Optional - shows 'iD-icon-wrench' if not set
53053 this.entityIds = attrs.entityIds || []; // Optional - used for hover-higlighting.
53055 this.autoArgs = attrs.autoArgs; // Optional - pass [actions, annotation] arglist if this fix can automatically run
53057 this.issue = null; // Generated link - added by validationIssue
53060 var buildRuleChecks = function buildRuleChecks() {
53062 equals: function equals(_equals) {
53063 return function (tags) {
53064 return Object.keys(_equals).every(function (k) {
53065 return _equals[k] === tags[k];
53069 notEquals: function notEquals(_notEquals) {
53070 return function (tags) {
53071 return Object.keys(_notEquals).some(function (k) {
53072 return _notEquals[k] !== tags[k];
53076 absence: function absence(_absence) {
53077 return function (tags) {
53078 return Object.keys(tags).indexOf(_absence) === -1;
53081 presence: function presence(_presence) {
53082 return function (tags) {
53083 return Object.keys(tags).indexOf(_presence) > -1;
53086 greaterThan: function greaterThan(_greaterThan) {
53087 var key = Object.keys(_greaterThan)[0];
53088 var value = _greaterThan[key];
53089 return function (tags) {
53090 return tags[key] > value;
53093 greaterThanEqual: function greaterThanEqual(_greaterThanEqual) {
53094 var key = Object.keys(_greaterThanEqual)[0];
53095 var value = _greaterThanEqual[key];
53096 return function (tags) {
53097 return tags[key] >= value;
53100 lessThan: function lessThan(_lessThan) {
53101 var key = Object.keys(_lessThan)[0];
53102 var value = _lessThan[key];
53103 return function (tags) {
53104 return tags[key] < value;
53107 lessThanEqual: function lessThanEqual(_lessThanEqual) {
53108 var key = Object.keys(_lessThanEqual)[0];
53109 var value = _lessThanEqual[key];
53110 return function (tags) {
53111 return tags[key] <= value;
53114 positiveRegex: function positiveRegex(_positiveRegex) {
53115 var tagKey = Object.keys(_positiveRegex)[0];
53117 var expression = _positiveRegex[tagKey].join('|');
53119 var regex = new RegExp(expression);
53120 return function (tags) {
53121 return regex.test(tags[tagKey]);
53124 negativeRegex: function negativeRegex(_negativeRegex) {
53125 var tagKey = Object.keys(_negativeRegex)[0];
53127 var expression = _negativeRegex[tagKey].join('|');
53129 var regex = new RegExp(expression);
53130 return function (tags) {
53131 return !regex.test(tags[tagKey]);
53137 var buildLineKeys = function buildLineKeys() {
53153 var serviceMapRules = {
53154 init: function init() {
53155 this._ruleChecks = buildRuleChecks();
53156 this._validationRules = [];
53157 this._areaKeys = osmAreaKeys;
53158 this._lineKeys = buildLineKeys();
53160 // list of rules only relevant to tag checks...
53161 filterRuleChecks: function filterRuleChecks(selector) {
53162 var _ruleChecks = this._ruleChecks;
53163 return Object.keys(selector).reduce(function (rules, key) {
53164 if (['geometry', 'error', 'warning'].indexOf(key) === -1) {
53165 rules.push(_ruleChecks[key](selector[key]));
53171 // builds tagMap from mapcss-parse selector object...
53172 buildTagMap: function buildTagMap(selector) {
53173 var getRegexValues = function getRegexValues(regexes) {
53174 return regexes.map(function (regex) {
53175 return regex.replace(/\$|\^/g, '');
53179 var tagMap = Object.keys(selector).reduce(function (expectedTags, key) {
53181 var isRegex = /regex/gi.test(key);
53182 var isEqual = /equals/gi.test(key);
53184 if (isRegex || isEqual) {
53185 Object.keys(selector[key]).forEach(function (selectorKey) {
53186 values = isEqual ? [selector[key][selectorKey]] : getRegexValues(selector[key][selectorKey]);
53188 if (expectedTags.hasOwnProperty(selectorKey)) {
53189 values = values.concat(expectedTags[selectorKey]);
53192 expectedTags[selectorKey] = values;
53194 } else if (/(greater|less)Than(Equal)?|presence/g.test(key)) {
53195 var tagKey = /presence/.test(key) ? selector[key] : Object.keys(selector[key])[0];
53196 values = [selector[key][tagKey]];
53198 if (expectedTags.hasOwnProperty(tagKey)) {
53199 values = values.concat(expectedTags[tagKey]);
53202 expectedTags[tagKey] = values;
53205 return expectedTags;
53209 // inspired by osmWay#isArea()
53210 inferGeometry: function inferGeometry(tagMap) {
53211 var _lineKeys = this._lineKeys;
53212 var _areaKeys = this._areaKeys;
53214 var keyValueDoesNotImplyArea = function keyValueDoesNotImplyArea(key) {
53215 return utilArrayIntersection(tagMap[key], Object.keys(_areaKeys[key])).length > 0;
53218 var keyValueImpliesLine = function keyValueImpliesLine(key) {
53219 return utilArrayIntersection(tagMap[key], Object.keys(_lineKeys[key])).length > 0;
53222 if (tagMap.hasOwnProperty('area')) {
53223 if (tagMap.area.indexOf('yes') > -1) {
53227 if (tagMap.area.indexOf('no') > -1) {
53232 for (var key in tagMap) {
53233 if (key in _areaKeys && !keyValueDoesNotImplyArea(key)) {
53237 if (key in _lineKeys && keyValueImpliesLine(key)) {
53244 // adds from mapcss-parse selector check...
53245 addRule: function addRule(selector) {
53247 // checks relevant to mapcss-selector
53248 checks: this.filterRuleChecks(selector),
53249 // true if all conditions for a tag error are true..
53250 matches: function matches(entity) {
53251 return this.checks.every(function (check) {
53252 return check(entity.tags);
53255 // borrowed from Way#isArea()
53256 inferredGeometry: this.inferGeometry(this.buildTagMap(selector), this._areaKeys),
53257 geometryMatches: function geometryMatches(entity, graph) {
53258 if (entity.type === 'node' || entity.type === 'relation') {
53259 return selector.geometry === entity.type;
53260 } else if (entity.type === 'way') {
53261 return this.inferredGeometry === entity.geometry(graph);
53264 // when geometries match and tag matches are present, return a warning...
53265 findIssues: function findIssues(entity, graph, issues) {
53266 if (this.geometryMatches(entity, graph) && this.matches(entity)) {
53267 var severity = Object.keys(selector).indexOf('error') > -1 ? 'error' : 'warning';
53268 var _message = selector[severity];
53269 issues.push(new validationIssue({
53271 severity: severity,
53272 message: function message() {
53275 entityIds: [entity.id]
53281 this._validationRules.push(rule);
53283 clearRules: function clearRules() {
53284 this._validationRules = [];
53286 // returns validationRules...
53287 validationRules: function validationRules() {
53288 return this._validationRules;
53290 // returns ruleChecks
53291 ruleChecks: function ruleChecks() {
53292 return this._ruleChecks;
53296 var apibase$2 = 'https://nominatim.openstreetmap.org/';
53297 var _inflight$2 = {};
53299 var _nominatimCache;
53301 var serviceNominatim = {
53302 init: function init() {
53304 _nominatimCache = new RBush();
53306 reset: function reset() {
53307 Object.values(_inflight$2).forEach(function (controller) {
53308 controller.abort();
53311 _nominatimCache = new RBush();
53313 countryCode: function countryCode(location, callback) {
53314 this.reverse(location, function (err, result) {
53316 return callback(err);
53317 } else if (result.address) {
53318 return callback(null, result.address.country_code);
53320 return callback('Unable to geocode', null);
53324 reverse: function reverse(loc, callback) {
53325 var cached = _nominatimCache.search({
53332 if (cached.length > 0) {
53333 if (callback) callback(null, cached[0].data);
53344 var url = apibase$2 + 'reverse?' + utilQsString(params);
53345 if (_inflight$2[url]) return;
53346 var controller = new AbortController();
53347 _inflight$2[url] = controller;
53349 signal: controller.signal
53350 }).then(function (result) {
53351 delete _inflight$2[url];
53353 if (result && result.error) {
53354 throw new Error(result.error);
53357 var extent = geoExtent(loc).padByMeters(200);
53359 _nominatimCache.insert(Object.assign(extent.bbox(), {
53363 if (callback) callback(null, result);
53364 })["catch"](function (err) {
53365 delete _inflight$2[url];
53366 if (err.name === 'AbortError') return;
53367 if (callback) callback(err.message);
53370 search: function search(val, callback) {
53371 var searchVal = encodeURIComponent(val);
53372 var url = apibase$2 + 'search/' + searchVal + '?limit=10&format=json';
53373 if (_inflight$2[url]) return;
53374 var controller = new AbortController();
53375 _inflight$2[url] = controller;
53377 signal: controller.signal
53378 }).then(function (result) {
53379 delete _inflight$2[url];
53381 if (result && result.error) {
53382 throw new Error(result.error);
53385 if (callback) callback(null, result);
53386 })["catch"](function (err) {
53387 delete _inflight$2[url];
53388 if (err.name === 'AbortError') return;
53389 if (callback) callback(err.message);
53394 // for punction see https://stackoverflow.com/a/21224179
53396 function simplify$1(str) {
53397 if (typeof str !== 'string') return '';
53398 return diacritics.remove(str.replace(/&/g, 'and').replace(/İ/ig, 'i') // for BİM, İşbank - #5017
53399 .replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u2000-\u206f\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00-\u2e7f\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, '').toLowerCase());
53402 var matchGroups$1 = {adult_gaming_centre:["amenity/casino","amenity/gambling","leisure/adult_gaming_centre"],beauty:["shop/beauty","shop/hairdresser_supply"],bed:["shop/bed","shop/furniture"],beverages:["shop/alcohol","shop/beer","shop/beverages","shop/wine"],camping:["leisure/park","tourism/camp_site","tourism/caravan_site"],car_parts:["shop/car_parts","shop/car_repair","shop/tires","shop/tyres"],clinic:["amenity/clinic","amenity/doctors","healthcare/clinic","healthcare/dialysis"],confectionery:["shop/candy","shop/chocolate","shop/confectionery"],convenience:["shop/beauty","shop/chemist","shop/convenience","shop/cosmetics","shop/grocery","shop/newsagent"],coworking:["amenity/coworking_space","office/coworking","office/coworking_space"],dentist:["amenity/dentist","amenity/doctors","healthcare/dentist"],electronics:["office/telecommunication","shop/computer","shop/electronics","shop/hifi","shop/mobile","shop/mobile_phone","shop/telecommunication"],fabric:["shop/fabric","shop/haberdashery","shop/sewing"],fashion:["shop/accessories","shop/bag","shop/botique","shop/clothes","shop/department_store","shop/fashion","shop/fashion_accessories","shop/sports","shop/shoes"],financial:["amenity/bank","office/accountant","office/financial","office/financial_advisor","office/tax_advisor","shop/tax"],fitness:["leisure/fitness_centre","leisure/fitness_center","leisure/sports_centre","leisure/sports_center"],food:["amenity/pub","amenity/bar","amenity/cafe","amenity/fast_food","amenity/ice_cream","amenity/restaurant","shop/bakery","shop/ice_cream","shop/pastry","shop/tea","shop/coffee"],fuel:["amenity/fuel","shop/gas","shop/convenience;gas","shop/gas;convenience"],gift:["shop/gift","shop/card","shop/cards","shop/stationery"],hardware:["shop/bathroom_furnishing","shop/carpet","shop/diy","shop/doityourself","shop/doors","shop/electrical","shop/flooring","shop/hardware","shop/hardware_store","shop/power_tools","shop/tool_hire","shop/tools","shop/trade"],health_food:["shop/health","shop/health_food","shop/herbalist","shop/nutrition_supplements"],hobby:["shop/electronics","shop/hobby","shop/books","shop/games","shop/collector","shop/toys","shop/model","shop/video_games","shop/anime"],hospital:["amenity/doctors","amenity/hospital","healthcare/hospital"],houseware:["shop/houseware","shop/interior_decoration"],lifeboat_station:["amenity/lifeboat_station","emergency/lifeboat_station","emergency/marine_rescue"],lodging:["tourism/hotel","tourism/motel"],money_transfer:["amenity/money_transfer","shop/money_transfer"],office_supplies:["shop/office_supplies","shop/stationary","shop/stationery"],outdoor:["shop/outdoor","shop/sports"],pharmacy:["amenity/doctors","amenity/pharmacy","healthcare/pharmacy"],playground:["amenity/theme_park","leisure/amusement_arcade","leisure/playground"],rental:["amenity/bicycle_rental","amenity/boat_rental","amenity/car_rental","amenity/truck_rental","amenity/vehicle_rental","shop/rental"],school:["amenity/childcare","amenity/college","amenity/kindergarten","amenity/language_school","amenity/prep_school","amenity/school","amenity/university"],supermarket:["shop/food","shop/frozen_food","shop/greengrocer","shop/grocery","shop/supermarket","shop/wholesale"],variety_store:["shop/variety_store","shop/discount","shop/convenience"],vending:["amenity/vending_machine","shop/vending_machine"],storage:["shop/storage_units","shop/storage_rental"],weight_loss:["amenity/doctors","amenity/weight_clinic","healthcare/counselling","leisure/fitness_centre","office/therapist","shop/beauty","shop/diet","shop/food","shop/health_food","shop/herbalist","shop/nutrition","shop/nutrition_supplements","shop/weight_loss"],wholesale:["shop/wholesale","shop/supermarket","shop/department_store"]};
53403 var matchGroupsJSON = {
53404 matchGroups: matchGroups$1
53407 var genericWords = ["^(barn|bazaa?r|bench|bou?tique|building|casa|church)$","^(baseball|basketball|football|soccer|softball|tennis(halle)?)\\s?(field|court)?$","^(club|green|out|ware)\\s?house$","^(driveway|el árbol|fountain|golf|government|graveyard)$","^(hofladen|librairie|magazine?|maison)$","^(mobile home|skate)?\\s?park$","^(n\\s?\\/?\\s?a|name|no\\s?name|none|null|temporary|test|unknown)$","^(obuwie|pond|pool|sale|shops?|sklep|stores?)$","^\\?+$","^tattoo( studio)?$","^windmill$","^церковная( лавка)?$"];
53408 var genericWordsJSON = {
53409 genericWords: genericWords
53412 var trees$1 = {brands:{emoji:"🍔",mainTag:"brand:wikidata",sourceTags:["brand","name"],nameTags:{primary:"^(name|name:\\w+)$",alternate:"^(brand|brand:\\w+|operator|operator:\\w+|\\w+_name|\\w+_name:\\w+)$"}},flags:{emoji:"🚩",mainTag:"flag:wikidata",nameTags:{primary:"^(flag:name|flag:name:\\w+)$",alternate:"^(country|country:\\w+|flag|flag:\\w+|subject|subject:\\w+)$"}},operators:{emoji:"💼",mainTag:"operator:wikidata",sourceTags:["operator"],nameTags:{primary:"^(name|name:\\w+|operator|operator:\\w+)$",alternate:"^(brand|brand:\\w+|\\w+_name|\\w+_name:\\w+)$"}},transit:{emoji:"🚇",mainTag:"network:wikidata",sourceTags:["network"],nameTags:{primary:"^network$",alternate:"^(operator|operator:\\w+|network:\\w+|\\w+_name|\\w+_name:\\w+)$"}}};
53417 var matchGroups = matchGroupsJSON.matchGroups;
53418 var trees = treesJSON.trees;
53419 var Matcher = /*#__PURE__*/function () {
53422 // initialize the genericWords regexes
53423 function Matcher() {
53426 _classCallCheck$1(this, Matcher);
53428 // The `matchIndex` is a specialized structure that allows us to quickly answer
53429 // _"Given a [key/value tagpair, name, location], what canonical items (brands etc) can match it?"_
53431 // The index contains all valid combinations of k/v tagpairs and names
53435 // 'primary': Map (String 'nsimple' -> Set (itemIDs…), // matches for tags like `name`, `name:xx`, etc.
53436 // 'alternate': Map (String 'nsimple' -> Set (itemIDs…), // matches for tags like `alt_name`, `brand`, etc.
53437 // 'excludeNamed': Map (String 'pattern' -> RegExp),
53438 // 'excludeGeneric': Map (String 'pattern' -> RegExp)
53443 // 'amenity/bank': {
53445 // 'firstbank': Set ("firstbank-978cca", "firstbank-9794e6", "firstbank-f17495", …),
53449 // '1stbank': Set ("firstbank-f17495"),
53453 // 'shop/supermarket': {
53455 // 'coop': Set ("coop-76454b", "coop-ebf2d9", "coop-36e991", …),
53456 // 'coopfood': Set ("coopfood-a8278b", …),
53460 // 'coop': Set ("coopfood-a8278b", …),
53461 // 'federatedcooperatives': Set ("coop-76454b", …),
53462 // 'thecooperative': Set ("coopfood-a8278b", …),
53468 this.matchIndex = undefined; // The `genericWords` structure matches the contents of genericWords.json to instantiated RegExp objects
53469 // Map (String 'pattern' -> RegExp),
53471 this.genericWords = new Map();
53472 (genericWordsJSON.genericWords || []).forEach(function (s) {
53473 return _this.genericWords.set(s, new RegExp(s, 'i'));
53474 }); // The `itemLocation` structure maps itemIDs to locationSetIDs:
53476 // 'firstbank-f17495': '+[first_bank_western_us.geojson]',
53477 // 'firstbank-978cca': '+[first_bank_carolinas.geojson]',
53478 // 'coop-76454b': '+[Q16]',
53479 // 'coopfood-a8278b': '+[Q23666]',
53483 this.itemLocation = undefined; // The `locationSets` structure maps locationSetIDs to *resolved* locationSets:
53485 // '+[first_bank_western_us.geojson]': GeoJSON {…},
53486 // '+[first_bank_carolinas.geojson]': GeoJSON {…},
53487 // '+[Q16]': GeoJSON {…},
53488 // '+[Q23666]': GeoJSON {…},
53492 this.locationSets = undefined; // The `locationIndex` is an instance of which-polygon spatial index for the locationSets.
53494 this.locationIndex = undefined; // Array of match conflict pairs (currently unused)
53496 this.warnings = [];
53498 // `buildMatchIndex()`
53499 // Call this to prepare the matcher for use
53501 // `data` needs to be an Object indexed on a 'tree/key/value' path.
53502 // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
53504 // 'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
53505 // 'brands/amenity/bar': { properties: {}, items: [ {}, {}, … ] },
53511 _createClass$1(Matcher, [{
53512 key: "buildMatchIndex",
53513 value: function buildMatchIndex(data) {
53515 if (that.matchIndex) return; // it was built already
53517 that.matchIndex = new Map();
53518 Object.keys(data).forEach(function (tkv) {
53519 var category = data[tkv];
53520 var parts = tkv.split('/', 3); // tkv = "tree/key/value"
53525 var thiskv = "".concat(k, "/").concat(v);
53526 var tree = trees[t];
53527 var branch = that.matchIndex.get(thiskv);
53531 primary: new Map(),
53532 alternate: new Map(),
53533 excludeGeneric: new Map(),
53534 excludeNamed: new Map()
53536 that.matchIndex.set(thiskv, branch);
53537 } // ADD EXCLUSIONS
53540 var properties = category.properties || {};
53541 var exclude = properties.exclude || {};
53542 (exclude.generic || []).forEach(function (s) {
53543 return branch.excludeGeneric.set(s, new RegExp(s, 'i'));
53545 (exclude.named || []).forEach(function (s) {
53546 return branch.excludeNamed.set(s, new RegExp(s, 'i'));
53548 var excludeRegexes = [].concat(_toConsumableArray(branch.excludeGeneric.values()), _toConsumableArray(branch.excludeNamed.values())); // ADD ITEMS
53550 var items = category.items;
53551 if (!Array.isArray(items) || !items.length) return; // Primary name patterns, match tags to take first
53552 // e.g. `name`, `name:ru`
53554 var primaryName = new RegExp(tree.nameTags.primary, 'i'); // Alternate name patterns, match tags to consider after primary
53555 // e.g. `alt_name`, `short_name`, `brand`, `brand:ru`, etc..
53557 var alternateName = new RegExp(tree.nameTags.alternate, 'i'); // There are a few exceptions to the name matching regexes.
53558 // Usually a tag suffix contains a language code like `name:en`, `name:ru`
53559 // but we want to exclude things like `operator:type`, `name:etymology`, etc..
53561 var notName = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i; // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
53563 var skipGenericKV = skipGenericKVMatches(t, k, v); // We will collect the generic KV pairs anyway (for the purpose of filtering them out of matchTags)
53565 var genericKV = new Set(["".concat(k, "/yes"), "building/yes"]); // Collect alternate tagpairs for this kv category from matchGroups.
53566 // We might also pick up a few more generic KVs (like `shop/yes`)
53568 var matchGroupKV = new Set();
53569 Object.values(matchGroups).forEach(function (matchGroup) {
53570 var inGroup = matchGroup.some(function (otherkv) {
53571 return otherkv === thiskv;
53573 if (!inGroup) return;
53574 matchGroup.forEach(function (otherkv) {
53575 if (otherkv === thiskv) return; // skip self
53577 matchGroupKV.add(otherkv);
53578 var otherk = otherkv.split('/', 2)[0]; // we might pick up a `shop/yes`
53580 genericKV.add("".concat(otherk, "/yes"));
53582 }); // For each item, insert all [key, value, name] combinations into the match index
53584 items.forEach(function (item) {
53585 if (!item.id) return; // Automatically remove redundant `matchTags` - #3417
53586 // (i.e. This kv is already covered by matchGroups, so it doesn't need to be in `item.matchTags`)
53588 if (Array.isArray(item.matchTags) && item.matchTags.length) {
53589 item.matchTags = item.matchTags.filter(function (matchTag) {
53590 return !matchGroupKV.has(matchTag) && !genericKV.has(matchTag);
53592 if (!item.matchTags.length) delete item.matchTags;
53593 } // key/value tagpairs to insert into the match index..
53596 var kvTags = ["".concat(thiskv)].concat(item.matchTags || []);
53598 if (!skipGenericKV) {
53599 kvTags = kvTags.concat(Array.from(genericKV)); // #3454 - match some generic tags
53600 } // Index all the namelike tag values
53603 Object.keys(item.tags).forEach(function (osmkey) {
53604 if (notName.test(osmkey)) return; // osmkey is not a namelike tag, skip
53606 var osmvalue = item.tags[osmkey];
53607 if (!osmvalue || excludeRegexes.some(function (regex) {
53608 return regex.test(osmvalue);
53609 })) return; // osmvalue missing or excluded
53611 if (primaryName.test(osmkey)) {
53612 kvTags.forEach(function (kv) {
53613 return insertName('primary', kv, simplify$1(osmvalue), item.id);
53615 } else if (alternateName.test(osmkey)) {
53616 kvTags.forEach(function (kv) {
53617 return insertName('alternate', kv, simplify$1(osmvalue), item.id);
53620 }); // Index `matchNames` after indexing all other names..
53622 var keepMatchNames = new Set();
53623 (item.matchNames || []).forEach(function (matchName) {
53624 // If this matchname isn't already indexed, add it to the alternate index
53625 var nsimple = simplify$1(matchName);
53626 kvTags.forEach(function (kv) {
53627 var branch = that.matchIndex.get(kv);
53628 var primaryLeaf = branch && branch.primary.get(nsimple);
53629 var alternateLeaf = branch && branch.alternate.get(nsimple);
53630 var inPrimary = primaryLeaf && primaryLeaf.has(item.id);
53631 var inAlternate = alternateLeaf && alternateLeaf.has(item.id);
53633 if (!inPrimary && !inAlternate) {
53634 insertName('alternate', kv, nsimple, item.id);
53635 keepMatchNames.add(matchName);
53638 }); // Automatically remove redundant `matchNames` - #3417
53639 // (i.e. This name got indexed some other way, so it doesn't need to be in `item.matchNames`)
53641 if (keepMatchNames.size) {
53642 item.matchNames = Array.from(keepMatchNames);
53644 delete item.matchNames;
53648 // Insert this item into the matchIndex
53650 function insertName(which, kv, nsimple, itemID) {
53651 if (!nsimple) return;
53652 var branch = that.matchIndex.get(kv);
53656 primary: new Map(),
53657 alternate: new Map(),
53658 excludeGeneric: new Map(),
53659 excludeNamed: new Map()
53661 that.matchIndex.set(kv, branch);
53664 var leaf = branch[which].get(nsimple);
53668 branch[which].set(nsimple, leaf);
53671 leaf.add(itemID); // insert
53672 } // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
53675 function skipGenericKVMatches(t, k, v) {
53676 return t === 'flags' || t === 'transit' || k === 'landuse' || v === 'atm' || v === 'bicycle_parking' || v === 'car_sharing' || v === 'caravan_site' || v === 'charging_station' || v === 'dog_park' || v === 'parking' || v === 'phone' || v === 'playground' || v === 'post_box' || v === 'public_bookcase' || v === 'recycling' || v === 'vending_machine';
53679 // `buildLocationIndex()`
53680 // Call this to prepare a which-polygon location index.
53681 // This *resolves* all the locationSets into GeoJSON, which takes some time.
53682 // You can skip this step if you don't care about matching within a location.
53684 // `data` needs to be an Object indexed on a 'tree/key/value' path.
53685 // (e.g. cache filled by `fileTree.read` or data found in `dist/nsi.json`)
53687 // 'brands/amenity/bank': { properties: {}, items: [ {}, {}, … ] },
53688 // 'brands/amenity/bar': { properties: {}, items: [ {}, {}, … ] },
53694 key: "buildLocationIndex",
53695 value: function buildLocationIndex(data, loco) {
53697 if (that.locationIndex) return; // it was built already
53699 that.itemLocation = new Map();
53700 that.locationSets = new Map();
53701 Object.keys(data).forEach(function (tkv) {
53702 var items = data[tkv].items;
53703 if (!Array.isArray(items) || !items.length) return;
53704 items.forEach(function (item) {
53705 if (that.itemLocation.has(item.id)) return; // we've seen item id already - shouldn't be possible?
53710 resolved = loco.resolveLocationSet(item.locationSet); // resolve a feature for this locationSet
53712 console.warn("buildLocationIndex: ".concat(err.message)); // couldn't resolve
53715 if (!resolved || !resolved.id) return;
53716 that.itemLocation.set(item.id, resolved.id); // link it to the item
53718 if (that.locationSets.has(resolved.id)) return; // we've seen this locationSet feature before..
53719 // First time seeing this locationSet feature, make a copy and add to locationSet cache..
53721 var feature = _cloneDeep(resolved.feature);
53723 feature.id = resolved.id; // Important: always use the locationSet `id` (`+[Q30]`), not the feature `id` (`Q30`)
53725 feature.properties.id = resolved.id;
53727 if (!feature.geometry.coordinates.length || !feature.properties.area) {
53728 console.warn("buildLocationIndex: locationSet ".concat(resolved.id, " for ").concat(item.id, " resolves to an empty feature:"));
53729 console.warn(JSON.stringify(feature));
53733 that.locationSets.set(resolved.id, feature);
53736 that.locationIndex = whichPolygon_1({
53737 type: 'FeatureCollection',
53738 features: _toConsumableArray(that.locationSets.values())
53741 function _cloneDeep(obj) {
53742 return JSON.parse(JSON.stringify(obj));
53746 // Pass parts and return an Array of matches.
53750 // `loc` - optional - [lon,lat] location to search
53752 // 1. If the [k,v,n] tuple matches a canonical item…
53753 // Return an Array of match results.
53754 // Each result will include the area in km² that the item is valid.
53756 // Order of results:
53757 // Primary ordering will be on the "match" column:
53758 // "primary" - where the query matches the `name` tag, followed by
53759 // "alternate" - where the query matches an alternate name tag (e.g. short_name, brand, operator, etc)
53760 // Secondary ordering will be on the "area" column:
53761 // "area descending" if no location was provided, (worldwide before local)
53762 // "area ascending" if location was provided (local before worldwide)
53765 // { match: 'primary', itemID: String, area: Number, kv: String, nsimple: String },
53766 // { match: 'primary', itemID: String, area: Number, kv: String, nsimple: String },
53767 // { match: 'alternate', itemID: String, area: Number, kv: String, nsimple: String },
53768 // { match: 'alternate', itemID: String, area: Number, kv: String, nsimple: String },
53774 // 2. If the [k,v,n] tuple matches an exclude pattern…
53775 // Return an Array with a single exclude result, either
53777 // [ { match: 'excludeGeneric', pattern: String, kv: String } ] // "generic" e.g. "Food Court"
53779 // [ { match: 'excludeNamed', pattern: String, kv: String } ] // "named", e.g. "Kebabai"
53782 // "generic" - a generic word that is probably not really a name.
53783 // For these, iD should warn the user "Hey don't put 'food court' in the name tag".
53784 // "named" - a real name like "Kebabai" that is just common, but not a brand.
53785 // For these, iD should just let it be. We don't include these in NSI, but we don't want to nag users about it either.
53789 // 3. If the [k,v,n] tuple matches nothing of any kind, return `null`
53795 value: function match(k, v, n, loc) {
53798 if (!that.matchIndex) {
53799 throw new Error('match: matchIndex not built.');
53800 } // If we were supplied a location, and a that.locationIndex has been set up,
53801 // get the locationSets that are valid there so we can filter results.
53804 var matchLocations;
53806 if (Array.isArray(loc) && that.locationIndex) {
53807 // which-polygon query returns an array of GeoJSON properties, pass true to return all results
53808 matchLocations = that.locationIndex([loc[0], loc[1], loc[0], loc[1]], true);
53811 var nsimple = simplify$1(n);
53812 var seen = new Set();
53814 gatherResults('primary');
53815 gatherResults('alternate');
53816 if (results.length) return results;
53817 gatherResults('exclude');
53818 return results.length ? results : null;
53820 function gatherResults(which) {
53821 // First try an exact match on k/v
53822 var kv = "".concat(k, "/").concat(v);
53823 var didMatch = tryMatch(which, kv);
53824 if (didMatch) return; // If that didn't work, look in match groups for other pairs considered equivalent to k/v..
53826 for (var mg in matchGroups) {
53827 var matchGroup = matchGroups[mg];
53828 var inGroup = matchGroup.some(function (otherkv) {
53829 return otherkv === kv;
53831 if (!inGroup) continue;
53833 for (var i = 0; i < matchGroup.length; i++) {
53834 var otherkv = matchGroup[i];
53835 if (otherkv === kv) continue; // skip self
53837 didMatch = tryMatch(which, otherkv);
53838 if (didMatch) return;
53840 } // If finished 'exclude' pass and still haven't matched anything, try the global `genericWords.json` patterns
53843 if (which === 'exclude') {
53844 var regex = _toConsumableArray(that.genericWords.values()).find(function (regex) {
53845 return regex.test(n);
53850 match: 'excludeGeneric',
53851 pattern: String(regex)
53852 }); // note no `branch`, no `kv`
53859 function tryMatch(which, kv) {
53860 var branch = that.matchIndex.get(kv);
53861 if (!branch) return;
53863 if (which === 'exclude') {
53864 // Test name `n` against named and generic exclude patterns
53865 var regex = _toConsumableArray(branch.excludeNamed.values()).find(function (regex) {
53866 return regex.test(n);
53871 match: 'excludeNamed',
53872 pattern: String(regex),
53878 regex = _toConsumableArray(branch.excludeGeneric.values()).find(function (regex) {
53879 return regex.test(n);
53884 match: 'excludeGeneric',
53885 pattern: String(regex),
53894 var leaf = branch[which].get(nsimple);
53895 if (!leaf || !leaf.size) return; // If we get here, we matched something..
53896 // Prepare the results, calculate areas (if location index was set up)
53898 var hits = Array.from(leaf).map(function (itemID) {
53899 var area = Infinity;
53901 if (that.itemLocation && that.locationSets) {
53902 var location = that.locationSets.get(that.itemLocation.get(itemID));
53903 area = location && location.properties.area || Infinity;
53914 var sortFn = byAreaDescending; // Filter the match to include only results valid in the requested `loc`..
53916 if (matchLocations) {
53917 hits = hits.filter(isValidLocation);
53918 sortFn = byAreaAscending;
53921 if (!hits.length) return; // push results
53923 hits.sort(sortFn).forEach(function (hit) {
53924 if (seen.has(hit.itemID)) return;
53925 seen.add(hit.itemID);
53930 function isValidLocation(hit) {
53931 if (!that.itemLocation) return true;
53932 return matchLocations.find(function (props) {
53933 return props.id === that.itemLocation.get(hit.itemID);
53935 } // Sort smaller (more local) locations first.
53938 function byAreaAscending(hitA, hitB) {
53939 return hitA.area - hitB.area;
53940 } // Sort larger (more worldwide) locations first.
53943 function byAreaDescending(hitA, hitB) {
53944 return hitB.area - hitA.area;
53949 // Return any warnings discovered when buiding the index.
53950 // (currently this does nothing)
53954 key: "getWarnings",
53955 value: function getWarnings() {
53956 return this.warnings;
53964 * Checks if `value` is the
53965 * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)
53966 * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
53972 * @param {*} value The value to check.
53973 * @returns {boolean} Returns `true` if `value` is an object, else `false`.
53979 * _.isObject([1, 2, 3]);
53982 * _.isObject(_.noop);
53985 * _.isObject(null);
53988 function isObject$2(value) {
53989 var type = _typeof(value);
53991 return value != null && (type == 'object' || type == 'function');
53994 /** Detect free variable `global` from Node.js. */
53995 var freeGlobal = (typeof global === "undefined" ? "undefined" : _typeof(global)) == 'object' && global && global.Object === Object && global;
53997 /** Detect free variable `self`. */
53999 var freeSelf = (typeof self === "undefined" ? "undefined" : _typeof(self)) == 'object' && self && self.Object === Object && self;
54000 /** Used as a reference to the global object. */
54002 var root = freeGlobal || freeSelf || Function('return this')();
54005 * Gets the timestamp of the number of milliseconds that have elapsed since
54006 * the Unix epoch (1 January 1970 00:00:00 UTC).
54012 * @returns {number} Returns the timestamp.
54015 * _.defer(function(stamp) {
54016 * console.log(_.now() - stamp);
54018 * // => Logs the number of milliseconds it took for the deferred invocation.
54021 var now = function now() {
54022 return root.Date.now();
54025 /** Used to match a single whitespace character. */
54026 var reWhitespace = /\s/;
54028 * Used by `_.trim` and `_.trimEnd` to get the index of the last non-whitespace
54029 * character of `string`.
54032 * @param {string} string The string to inspect.
54033 * @returns {number} Returns the index of the last non-whitespace character.
54036 function trimmedEndIndex(string) {
54037 var index = string.length;
54039 while (index-- && reWhitespace.test(string.charAt(index))) {}
54044 /** Used to match leading whitespace. */
54046 var reTrimStart = /^\s+/;
54048 * The base implementation of `_.trim`.
54051 * @param {string} string The string to trim.
54052 * @returns {string} Returns the trimmed string.
54055 function baseTrim(string) {
54056 return string ? string.slice(0, trimmedEndIndex(string) + 1).replace(reTrimStart, '') : string;
54059 /** Built-in value references. */
54061 var _Symbol = root.Symbol;
54063 /** Used for built-in method references. */
54065 var objectProto$1 = Object.prototype;
54066 /** Used to check objects for own properties. */
54068 var hasOwnProperty$2 = objectProto$1.hasOwnProperty;
54070 * Used to resolve the
54071 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
54075 var nativeObjectToString$1 = objectProto$1.toString;
54076 /** Built-in value references. */
54078 var symToStringTag$1 = _Symbol ? _Symbol.toStringTag : undefined;
54080 * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
54083 * @param {*} value The value to query.
54084 * @returns {string} Returns the raw `toStringTag`.
54087 function getRawTag(value) {
54088 var isOwn = hasOwnProperty$2.call(value, symToStringTag$1),
54089 tag = value[symToStringTag$1];
54092 value[symToStringTag$1] = undefined;
54093 var unmasked = true;
54096 var result = nativeObjectToString$1.call(value);
54100 value[symToStringTag$1] = tag;
54102 delete value[symToStringTag$1];
54109 /** Used for built-in method references. */
54110 var objectProto = Object.prototype;
54112 * Used to resolve the
54113 * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
54117 var nativeObjectToString = objectProto.toString;
54119 * Converts `value` to a string using `Object.prototype.toString`.
54122 * @param {*} value The value to convert.
54123 * @returns {string} Returns the converted string.
54126 function objectToString(value) {
54127 return nativeObjectToString.call(value);
54130 /** `Object#toString` result references. */
54132 var nullTag = '[object Null]',
54133 undefinedTag = '[object Undefined]';
54134 /** Built-in value references. */
54136 var symToStringTag = _Symbol ? _Symbol.toStringTag : undefined;
54138 * The base implementation of `getTag` without fallbacks for buggy environments.
54141 * @param {*} value The value to query.
54142 * @returns {string} Returns the `toStringTag`.
54145 function baseGetTag(value) {
54146 if (value == null) {
54147 return value === undefined ? undefinedTag : nullTag;
54150 return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString(value);
54154 * Checks if `value` is object-like. A value is object-like if it's not `null`
54155 * and has a `typeof` result of "object".
54161 * @param {*} value The value to check.
54162 * @returns {boolean} Returns `true` if `value` is object-like, else `false`.
54165 * _.isObjectLike({});
54168 * _.isObjectLike([1, 2, 3]);
54171 * _.isObjectLike(_.noop);
54174 * _.isObjectLike(null);
54177 function isObjectLike(value) {
54178 return value != null && _typeof(value) == 'object';
54181 /** `Object#toString` result references. */
54183 var symbolTag = '[object Symbol]';
54185 * Checks if `value` is classified as a `Symbol` primitive or object.
54191 * @param {*} value The value to check.
54192 * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.
54195 * _.isSymbol(Symbol.iterator);
54198 * _.isSymbol('abc');
54202 function isSymbol(value) {
54203 return _typeof(value) == 'symbol' || isObjectLike(value) && baseGetTag(value) == symbolTag;
54206 /** Used as references for various `Number` constants. */
54209 /** Used to detect bad signed hexadecimal string values. */
54211 var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
54212 /** Used to detect binary string values. */
54214 var reIsBinary = /^0b[01]+$/i;
54215 /** Used to detect octal string values. */
54217 var reIsOctal = /^0o[0-7]+$/i;
54218 /** Built-in method references without a dependency on `root`. */
54220 var freeParseInt = parseInt;
54222 * Converts `value` to a number.
54228 * @param {*} value The value to process.
54229 * @returns {number} Returns the number.
54235 * _.toNumber(Number.MIN_VALUE);
54238 * _.toNumber(Infinity);
54241 * _.toNumber('3.2');
54245 function toNumber(value) {
54246 if (typeof value == 'number') {
54250 if (isSymbol(value)) {
54254 if (isObject$2(value)) {
54255 var other = typeof value.valueOf == 'function' ? value.valueOf() : value;
54256 value = isObject$2(other) ? other + '' : other;
54259 if (typeof value != 'string') {
54260 return value === 0 ? value : +value;
54263 value = baseTrim(value);
54264 var isBinary = reIsBinary.test(value);
54265 return isBinary || reIsOctal.test(value) ? freeParseInt(value.slice(2), isBinary ? 2 : 8) : reIsBadHex.test(value) ? NAN : +value;
54268 /** Error message constants. */
54270 var FUNC_ERROR_TEXT$1 = 'Expected a function';
54271 /* Built-in method references for those with the same name as other `lodash` methods. */
54273 var nativeMax = Math.max,
54274 nativeMin = Math.min;
54276 * Creates a debounced function that delays invoking `func` until after `wait`
54277 * milliseconds have elapsed since the last time the debounced function was
54278 * invoked. The debounced function comes with a `cancel` method to cancel
54279 * delayed `func` invocations and a `flush` method to immediately invoke them.
54280 * Provide `options` to indicate whether `func` should be invoked on the
54281 * leading and/or trailing edge of the `wait` timeout. The `func` is invoked
54282 * with the last arguments provided to the debounced function. Subsequent
54283 * calls to the debounced function return the result of the last `func`
54286 * **Note:** If `leading` and `trailing` options are `true`, `func` is
54287 * invoked on the trailing edge of the timeout only if the debounced function
54288 * is invoked more than once during the `wait` timeout.
54290 * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
54291 * until to the next tick, similar to `setTimeout` with a timeout of `0`.
54293 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
54294 * for details over the differences between `_.debounce` and `_.throttle`.
54299 * @category Function
54300 * @param {Function} func The function to debounce.
54301 * @param {number} [wait=0] The number of milliseconds to delay.
54302 * @param {Object} [options={}] The options object.
54303 * @param {boolean} [options.leading=false]
54304 * Specify invoking on the leading edge of the timeout.
54305 * @param {number} [options.maxWait]
54306 * The maximum time `func` is allowed to be delayed before it's invoked.
54307 * @param {boolean} [options.trailing=true]
54308 * Specify invoking on the trailing edge of the timeout.
54309 * @returns {Function} Returns the new debounced function.
54312 * // Avoid costly calculations while the window size is in flux.
54313 * jQuery(window).on('resize', _.debounce(calculateLayout, 150));
54315 * // Invoke `sendMail` when clicked, debouncing subsequent calls.
54316 * jQuery(element).on('click', _.debounce(sendMail, 300, {
54318 * 'trailing': false
54321 * // Ensure `batchLog` is invoked once after 1 second of debounced calls.
54322 * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
54323 * var source = new EventSource('/stream');
54324 * jQuery(source).on('message', debounced);
54326 * // Cancel the trailing debounced invocation.
54327 * jQuery(window).on('popstate', debounced.cancel);
54330 function debounce(func, wait, options) {
54337 lastInvokeTime = 0,
54342 if (typeof func != 'function') {
54343 throw new TypeError(FUNC_ERROR_TEXT$1);
54346 wait = toNumber(wait) || 0;
54348 if (isObject$2(options)) {
54349 leading = !!options.leading;
54350 maxing = 'maxWait' in options;
54351 maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
54352 trailing = 'trailing' in options ? !!options.trailing : trailing;
54355 function invokeFunc(time) {
54356 var args = lastArgs,
54357 thisArg = lastThis;
54358 lastArgs = lastThis = undefined;
54359 lastInvokeTime = time;
54360 result = func.apply(thisArg, args);
54364 function leadingEdge(time) {
54365 // Reset any `maxWait` timer.
54366 lastInvokeTime = time; // Start the timer for the trailing edge.
54368 timerId = setTimeout(timerExpired, wait); // Invoke the leading edge.
54370 return leading ? invokeFunc(time) : result;
54373 function remainingWait(time) {
54374 var timeSinceLastCall = time - lastCallTime,
54375 timeSinceLastInvoke = time - lastInvokeTime,
54376 timeWaiting = wait - timeSinceLastCall;
54377 return maxing ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) : timeWaiting;
54380 function shouldInvoke(time) {
54381 var timeSinceLastCall = time - lastCallTime,
54382 timeSinceLastInvoke = time - lastInvokeTime; // Either this is the first call, activity has stopped and we're at the
54383 // trailing edge, the system time has gone backwards and we're treating
54384 // it as the trailing edge, or we've hit the `maxWait` limit.
54386 return lastCallTime === undefined || timeSinceLastCall >= wait || timeSinceLastCall < 0 || maxing && timeSinceLastInvoke >= maxWait;
54389 function timerExpired() {
54392 if (shouldInvoke(time)) {
54393 return trailingEdge(time);
54394 } // Restart the timer.
54397 timerId = setTimeout(timerExpired, remainingWait(time));
54400 function trailingEdge(time) {
54401 timerId = undefined; // Only invoke if we have `lastArgs` which means `func` has been
54402 // debounced at least once.
54404 if (trailing && lastArgs) {
54405 return invokeFunc(time);
54408 lastArgs = lastThis = undefined;
54412 function cancel() {
54413 if (timerId !== undefined) {
54414 clearTimeout(timerId);
54417 lastInvokeTime = 0;
54418 lastArgs = lastCallTime = lastThis = timerId = undefined;
54422 return timerId === undefined ? result : trailingEdge(now());
54425 function debounced() {
54427 isInvoking = shouldInvoke(time);
54428 lastArgs = arguments;
54430 lastCallTime = time;
54433 if (timerId === undefined) {
54434 return leadingEdge(lastCallTime);
54438 // Handle invocations in a tight loop.
54439 clearTimeout(timerId);
54440 timerId = setTimeout(timerExpired, wait);
54441 return invokeFunc(lastCallTime);
54445 if (timerId === undefined) {
54446 timerId = setTimeout(timerExpired, wait);
54452 debounced.cancel = cancel;
54453 debounced.flush = flush;
54458 iD.coreDifference represents the difference between two graphs.
54459 It knows how to calculate the set of entities that were
54460 created, modified, or deleted, and also contains the logic
54461 for recursively extending a difference to the complete set
54462 of entities that will require a redraw, taking into account
54463 child and parent relationships.
54466 function coreDifference(base, head) {
54468 var _didChange = {}; // 'addition', 'deletion', 'geometry', 'properties'
54472 function checkEntityID(id) {
54473 var h = head.entities[id];
54474 var b = base.entities[id];
54475 if (h === b) return;
54476 if (_changes[id]) return;
54483 _didChange.deletion = true;
54492 _didChange.addition = true;
54497 if (h.members && b.members && !fastDeepEqual(h.members, b.members)) {
54502 _didChange.geometry = true;
54503 _didChange.properties = true;
54507 if (h.loc && b.loc && !geoVecEqual(h.loc, b.loc)) {
54512 _didChange.geometry = true;
54515 if (h.nodes && b.nodes && !fastDeepEqual(h.nodes, b.nodes)) {
54520 _didChange.geometry = true;
54523 if (h.tags && b.tags && !fastDeepEqual(h.tags, b.tags)) {
54528 _didChange.properties = true;
54534 // HOT CODE: there can be many thousands of downloaded entities, so looping
54535 // through them all can become a performance bottleneck. Optimize by
54536 // resolving duplicates and using a basic `for` loop
54537 var ids = utilArrayUniq(Object.keys(head.entities).concat(Object.keys(base.entities)));
54539 for (var i = 0; i < ids.length; i++) {
54540 checkEntityID(ids[i]);
54546 _diff.length = function length() {
54547 return Object.keys(_changes).length;
54550 _diff.changes = function changes() {
54554 _diff.didChange = _didChange; // pass true to include affected relation members
54556 _diff.extantIDs = function extantIDs(includeRelMembers) {
54557 var result = new Set();
54558 Object.keys(_changes).forEach(function (id) {
54559 if (_changes[id].head) {
54563 var h = _changes[id].head;
54564 var b = _changes[id].base;
54565 var entity = h || b;
54567 if (includeRelMembers && entity.type === 'relation') {
54568 var mh = h ? h.members.map(function (m) {
54571 var mb = b ? b.members.map(function (m) {
54574 utilArrayUnion(mh, mb).forEach(function (memberID) {
54575 if (head.hasEntity(memberID)) {
54576 result.add(memberID);
54581 return Array.from(result);
54584 _diff.modified = function modified() {
54586 Object.values(_changes).forEach(function (change) {
54587 if (change.base && change.head) {
54588 result.push(change.head);
54594 _diff.created = function created() {
54596 Object.values(_changes).forEach(function (change) {
54597 if (!change.base && change.head) {
54598 result.push(change.head);
54604 _diff.deleted = function deleted() {
54606 Object.values(_changes).forEach(function (change) {
54607 if (change.base && !change.head) {
54608 result.push(change.base);
54614 _diff.summary = function summary() {
54616 var keys = Object.keys(_changes);
54618 for (var i = 0; i < keys.length; i++) {
54619 var change = _changes[keys[i]];
54621 if (change.head && change.head.geometry(head) !== 'vertex') {
54622 addEntity(change.head, head, change.base ? 'modified' : 'created');
54623 } else if (change.base && change.base.geometry(base) !== 'vertex') {
54624 addEntity(change.base, base, 'deleted');
54625 } else if (change.base && change.head) {
54627 var moved = !fastDeepEqual(change.base.loc, change.head.loc);
54628 var retagged = !fastDeepEqual(change.base.tags, change.head.tags);
54631 addParents(change.head);
54634 if (retagged || moved && change.head.hasInterestingTags()) {
54635 addEntity(change.head, head, 'modified');
54637 } else if (change.head && change.head.hasInterestingTags()) {
54639 addEntity(change.head, head, 'created');
54640 } else if (change.base && change.base.hasInterestingTags()) {
54642 addEntity(change.base, base, 'deleted');
54646 return Object.values(relevant);
54648 function addEntity(entity, graph, changeType) {
54649 relevant[entity.id] = {
54652 changeType: changeType
54656 function addParents(entity) {
54657 var parents = head.parentWays(entity);
54659 for (var j = parents.length - 1; j >= 0; j--) {
54660 var parent = parents[j];
54662 if (!(parent.id in relevant)) {
54663 addEntity(parent, head, 'modified');
54667 }; // returns complete set of entities that require a redraw
54668 // (optionally within given `extent`)
54671 _diff.complete = function complete(extent) {
54675 for (id in _changes) {
54676 change = _changes[id];
54677 var h = change.head;
54678 var b = change.base;
54679 var entity = h || b;
54682 if (extent && (!h || !h.intersects(extent, head)) && (!b || !b.intersects(extent, base))) {
54688 if (entity.type === 'way') {
54689 var nh = h ? h.nodes : [];
54690 var nb = b ? b.nodes : [];
54692 diff = utilArrayDifference(nh, nb);
54694 for (i = 0; i < diff.length; i++) {
54695 result[diff[i]] = head.hasEntity(diff[i]);
54698 diff = utilArrayDifference(nb, nh);
54700 for (i = 0; i < diff.length; i++) {
54701 result[diff[i]] = head.hasEntity(diff[i]);
54705 if (entity.type === 'relation' && entity.isMultipolygon()) {
54706 var mh = h ? h.members.map(function (m) {
54709 var mb = b ? b.members.map(function (m) {
54712 var ids = utilArrayUnion(mh, mb);
54714 for (i = 0; i < ids.length; i++) {
54715 var member = head.hasEntity(ids[i]);
54716 if (!member) continue; // not downloaded
54718 if (extent && !member.intersects(extent, head)) continue; // not visible
54720 result[ids[i]] = member;
54724 addParents(head.parentWays(entity), result);
54725 addParents(head.parentRelations(entity), result);
54730 function addParents(parents, result) {
54731 for (var i = 0; i < parents.length; i++) {
54732 var parent = parents[i];
54733 if (parent.id in result) continue;
54734 result[parent.id] = parent;
54735 addParents(head.parentRelations(parent), result);
54743 function coreTree(head) {
54744 // tree for entities
54745 var _rtree = new RBush();
54747 var _bboxes = {}; // maintain a separate tree for granular way segments
54749 var _segmentsRTree = new RBush();
54751 var _segmentsBBoxes = {};
54752 var _segmentsByWayId = {};
54755 function entityBBox(entity) {
54756 var bbox = entity.extent(head).bbox();
54757 bbox.id = entity.id;
54758 _bboxes[entity.id] = bbox;
54762 function segmentBBox(segment) {
54763 var extent = segment.extent(head); // extent can be null if the node entities aren't in the graph for some reason
54765 if (!extent) return null;
54766 var bbox = extent.bbox();
54767 bbox.segment = segment;
54768 _segmentsBBoxes[segment.id] = bbox;
54772 function removeEntity(entity) {
54773 _rtree.remove(_bboxes[entity.id]);
54775 delete _bboxes[entity.id];
54777 if (_segmentsByWayId[entity.id]) {
54778 _segmentsByWayId[entity.id].forEach(function (segment) {
54779 _segmentsRTree.remove(_segmentsBBoxes[segment.id]);
54781 delete _segmentsBBoxes[segment.id];
54784 delete _segmentsByWayId[entity.id];
54788 function loadEntities(entities) {
54789 _rtree.load(entities.map(entityBBox));
54792 entities.forEach(function (entity) {
54793 if (entity.segments) {
54794 var entitySegments = entity.segments(head); // cache these to make them easy to remove later
54796 _segmentsByWayId[entity.id] = entitySegments;
54797 segments = segments.concat(entitySegments);
54800 if (segments.length) _segmentsRTree.load(segments.map(segmentBBox).filter(Boolean));
54803 function updateParents(entity, insertions, memo) {
54804 head.parentWays(entity).forEach(function (way) {
54805 if (_bboxes[way.id]) {
54807 insertions[way.id] = way;
54810 updateParents(way, insertions, memo);
54812 head.parentRelations(entity).forEach(function (relation) {
54813 if (memo[entity.id]) return;
54814 memo[entity.id] = true;
54816 if (_bboxes[relation.id]) {
54817 removeEntity(relation);
54818 insertions[relation.id] = relation;
54821 updateParents(relation, insertions, memo);
54825 tree.rebase = function (entities, force) {
54826 var insertions = {};
54828 for (var i = 0; i < entities.length; i++) {
54829 var entity = entities[i];
54830 if (!entity.visible) continue;
54832 if (head.entities.hasOwnProperty(entity.id) || _bboxes[entity.id]) {
54835 } else if (_bboxes[entity.id]) {
54836 removeEntity(entity);
54840 insertions[entity.id] = entity;
54841 updateParents(entity, insertions, {});
54844 loadEntities(Object.values(insertions));
54848 function updateToGraph(graph) {
54849 if (graph === head) return;
54850 var diff = coreDifference(head, graph);
54852 var changed = diff.didChange;
54853 if (!changed.addition && !changed.deletion && !changed.geometry) return;
54854 var insertions = {};
54856 if (changed.deletion) {
54857 diff.deleted().forEach(function (entity) {
54858 removeEntity(entity);
54862 if (changed.geometry) {
54863 diff.modified().forEach(function (entity) {
54864 removeEntity(entity);
54865 insertions[entity.id] = entity;
54866 updateParents(entity, insertions, {});
54870 if (changed.addition) {
54871 diff.created().forEach(function (entity) {
54872 insertions[entity.id] = entity;
54876 loadEntities(Object.values(insertions));
54877 } // returns an array of entities with bounding boxes overlapping `extent` for the given `graph`
54880 tree.intersects = function (extent, graph) {
54881 updateToGraph(graph);
54882 return _rtree.search(extent.bbox()).map(function (bbox) {
54883 return graph.entity(bbox.id);
54885 }; // returns an array of segment objects with bounding boxes overlapping `extent` for the given `graph`
54888 tree.waySegments = function (extent, graph) {
54889 updateToGraph(graph);
54890 return _segmentsRTree.search(extent.bbox()).map(function (bbox) {
54891 return bbox.segment;
54898 function svgIcon(name, svgklass, useklass) {
54899 return function drawIcon(selection) {
54900 selection.selectAll('svg.icon' + (svgklass ? '.' + svgklass.split(' ')[0] : '')).data([0]).enter().append('svg').attr('class', 'icon ' + (svgklass || '')).append('use').attr('xlink:href', name).attr('class', useklass);
54904 function uiModal(selection, blocking) {
54907 var keybinding = utilKeybinding('modal');
54908 var previous = selection.select('div.modal');
54909 var animate = previous.empty();
54910 previous.transition().duration(200).style('opacity', 0).remove();
54911 var shaded = selection.append('div').attr('class', 'shaded').style('opacity', 0);
54913 shaded.close = function () {
54914 shaded.transition().duration(200).style('opacity', 0).remove();
54915 modal.transition().duration(200).style('top', '0px');
54916 select(document).call(keybinding.unbind);
54919 var modal = shaded.append('div').attr('class', 'modal fillL');
54920 modal.append('input').attr('class', 'keytrap keytrap-first').on('focus.keytrap', moveFocusToLast);
54923 shaded.on('click.remove-modal', function (d3_event) {
54924 if (d3_event.target === _this) {
54928 modal.append('button').attr('class', 'close').on('click', shaded.close).call(svgIcon('#iD-icon-close'));
54929 keybinding.on('⌫', shaded.close).on('⎋', shaded.close);
54930 select(document).call(keybinding);
54933 modal.append('div').attr('class', 'content');
54934 modal.append('input').attr('class', 'keytrap keytrap-last').on('focus.keytrap', moveFocusToFirst);
54937 shaded.transition().style('opacity', 1);
54939 shaded.style('opacity', 1);
54944 function moveFocusToFirst() {
54945 var node = modal // there are additional rules about what's focusable, but this suits our purposes
54946 .select('a, button, input:not(.keytrap), select, textarea').node();
54951 select(this).node().blur();
54955 function moveFocusToLast() {
54956 var nodes = modal.selectAll('a, button, input:not(.keytrap), select, textarea').nodes();
54958 if (nodes.length) {
54959 nodes[nodes.length - 1].focus();
54961 select(this).node().blur();
54966 function uiLoading(context) {
54967 var _modalSelection = select(null);
54970 var _blocking = false;
54972 var loading = function loading(selection) {
54973 _modalSelection = uiModal(selection, _blocking);
54975 var loadertext = _modalSelection.select('.content').classed('loading-modal', true).append('div').attr('class', 'modal-section fillL');
54977 loadertext.append('img').attr('class', 'loader').attr('src', context.imagePath('loader-white.gif'));
54978 loadertext.append('h3').html(_message);
54980 _modalSelection.select('button.close').attr('class', 'hide');
54985 loading.message = function (val) {
54986 if (!arguments.length) return _message;
54991 loading.blocking = function (val) {
54992 if (!arguments.length) return _blocking;
54997 loading.close = function () {
54998 _modalSelection.remove();
55001 loading.isShown = function () {
55002 return _modalSelection && !_modalSelection.empty() && _modalSelection.node().parentNode;
55008 function coreHistory(context) {
55009 var dispatch = dispatch$8('reset', 'change', 'merge', 'restore', 'undone', 'redone', 'storage_error');
55011 var _lock = utilSessionMutex('lock'); // restorable if iD not open in another window/tab and a saved history exists in localStorage
55014 var _hasUnresolvedRestorableChanges = _lock.lock() && !!corePreferences(getKey('saved_history'));
55016 var duration = 150;
55017 var _imageryUsed = [];
55018 var _photoOverlaysUsed = [];
55019 var _checkpoints = {};
55027 var _tree; // internal _act, accepts list of actions and eased time
55030 function _act(actions, t) {
55031 actions = Array.prototype.slice.call(actions);
55034 if (typeof actions[actions.length - 1] !== 'function') {
55035 annotation = actions.pop();
55038 var graph = _stack[_index].graph;
55040 for (var i = 0; i < actions.length; i++) {
55041 graph = actions[i](graph, t);
55046 annotation: annotation,
55047 imageryUsed: _imageryUsed,
55048 photoOverlaysUsed: _photoOverlaysUsed,
55049 transform: context.projection.transform(),
55050 selectedIDs: context.selectedIDs()
55052 } // internal _perform with eased time
55055 function _perform(args, t) {
55056 var previous = _stack[_index].graph;
55057 _stack = _stack.slice(0, _index + 1);
55059 var actionResult = _act(args, t);
55061 _stack.push(actionResult);
55064 return change(previous);
55065 } // internal _replace with eased time
55068 function _replace(args, t) {
55069 var previous = _stack[_index].graph; // assert(_index == _stack.length - 1)
55071 var actionResult = _act(args, t);
55073 _stack[_index] = actionResult;
55074 return change(previous);
55075 } // internal _overwrite with eased time
55078 function _overwrite(args, t) {
55079 var previous = _stack[_index].graph;
55087 _stack = _stack.slice(0, _index + 1);
55089 var actionResult = _act(args, t);
55091 _stack.push(actionResult);
55094 return change(previous);
55095 } // determine difference and dispatch a change event
55098 function change(previous) {
55099 var difference = coreDifference(previous, history.graph());
55101 if (!_pausedGraph) {
55102 dispatch.call('change', this, difference);
55106 } // iD uses namespaced keys so multiple installations do not conflict
55109 function getKey(n) {
55110 return 'iD_' + window.location.origin + '_' + n;
55114 graph: function graph() {
55115 return _stack[_index].graph;
55117 tree: function tree() {
55120 base: function base() {
55121 return _stack[0].graph;
55123 merge: function merge(entities
55126 var stack = _stack.map(function (state) {
55127 return state.graph;
55130 _stack[0].graph.rebase(entities, stack, false);
55132 _tree.rebase(entities, false);
55134 dispatch.call('merge', this, entities);
55136 perform: function perform() {
55137 // complete any transition already in progress
55138 select(document).interrupt('history.perform');
55139 var transitionable = false;
55140 var action0 = arguments[0];
55142 if (arguments.length === 1 || arguments.length === 2 && typeof arguments[1] !== 'function') {
55143 transitionable = !!action0.transitionable;
55146 if (transitionable) {
55147 var origArguments = arguments;
55148 select(document).transition('history.perform').duration(duration).ease(linear$1).tween('history.tween', function () {
55149 return function (t) {
55150 if (t < 1) _overwrite([action0], t);
55152 }).on('start', function () {
55153 _perform([action0], 0);
55154 }).on('end interrupt', function () {
55155 _overwrite(origArguments, 1);
55158 return _perform(arguments);
55161 replace: function replace() {
55162 select(document).interrupt('history.perform');
55163 return _replace(arguments, 1);
55165 // Same as calling pop and then perform
55166 overwrite: function overwrite() {
55167 select(document).interrupt('history.perform');
55168 return _overwrite(arguments, 1);
55170 pop: function pop(n) {
55171 select(document).interrupt('history.perform');
55172 var previous = _stack[_index].graph;
55174 if (isNaN(+n) || +n < 0) {
55178 while (n-- > 0 && _index > 0) {
55184 return change(previous);
55186 // Back to the previous annotated state or _index = 0.
55187 undo: function undo() {
55188 select(document).interrupt('history.perform');
55189 var previousStack = _stack[_index];
55190 var previous = previousStack.graph;
55192 while (_index > 0) {
55194 if (_stack[_index].annotation) break;
55197 dispatch.call('undone', this, _stack[_index], previousStack);
55198 return change(previous);
55200 // Forward to the next annotated state.
55201 redo: function redo() {
55202 select(document).interrupt('history.perform');
55203 var previousStack = _stack[_index];
55204 var previous = previousStack.graph;
55205 var tryIndex = _index;
55207 while (tryIndex < _stack.length - 1) {
55210 if (_stack[tryIndex].annotation) {
55212 dispatch.call('redone', this, _stack[_index], previousStack);
55217 return change(previous);
55219 pauseChangeDispatch: function pauseChangeDispatch() {
55220 if (!_pausedGraph) {
55221 _pausedGraph = _stack[_index].graph;
55224 resumeChangeDispatch: function resumeChangeDispatch() {
55225 if (_pausedGraph) {
55226 var previous = _pausedGraph;
55227 _pausedGraph = null;
55228 return change(previous);
55231 undoAnnotation: function undoAnnotation() {
55235 if (_stack[i].annotation) return _stack[i].annotation;
55239 redoAnnotation: function redoAnnotation() {
55240 var i = _index + 1;
55242 while (i <= _stack.length - 1) {
55243 if (_stack[i].annotation) return _stack[i].annotation;
55247 // Returns the entities from the active graph with bounding boxes
55248 // overlapping the given `extent`.
55249 intersects: function intersects(extent) {
55250 return _tree.intersects(extent, _stack[_index].graph);
55252 difference: function difference() {
55253 var base = _stack[0].graph;
55254 var head = _stack[_index].graph;
55255 return coreDifference(base, head);
55257 changes: function changes(action) {
55258 var base = _stack[0].graph;
55259 var head = _stack[_index].graph;
55262 head = action(head);
55265 var difference = coreDifference(base, head);
55267 modified: difference.modified(),
55268 created: difference.created(),
55269 deleted: difference.deleted()
55272 hasChanges: function hasChanges() {
55273 return this.difference().length() > 0;
55275 imageryUsed: function imageryUsed(sources) {
55277 _imageryUsed = sources;
55282 _stack.slice(1, _index + 1).forEach(function (state) {
55283 state.imageryUsed.forEach(function (source) {
55284 if (source !== 'Custom') {
55290 return Array.from(s);
55293 photoOverlaysUsed: function photoOverlaysUsed(sources) {
55295 _photoOverlaysUsed = sources;
55300 _stack.slice(1, _index + 1).forEach(function (state) {
55301 if (state.photoOverlaysUsed && Array.isArray(state.photoOverlaysUsed)) {
55302 state.photoOverlaysUsed.forEach(function (photoOverlay) {
55303 s.add(photoOverlay);
55308 return Array.from(s);
55311 // save the current history state
55312 checkpoint: function checkpoint(key) {
55313 _checkpoints[key] = {
55319 // restore history state to a given checkpoint or reset completely
55320 reset: function reset(key) {
55321 if (key !== undefined && _checkpoints.hasOwnProperty(key)) {
55322 _stack = _checkpoints[key].stack;
55323 _index = _checkpoints[key].index;
55329 _tree = coreTree(_stack[0].graph);
55333 dispatch.call('reset');
55334 dispatch.call('change');
55337 // `toIntroGraph()` is used to export the intro graph used by the walkthrough.
55340 // 1. Start the walkthrough.
55341 // 2. Get to a "free editing" tutorial step
55342 // 3. Make your edits to the walkthrough map
55343 // 4. In your browser dev console run:
55344 // `id.history().toIntroGraph()`
55345 // 5. This outputs stringified JSON to the browser console
55346 // 6. Copy it to `data/intro_graph.json` and prettify it in your code editor
55347 toIntroGraph: function toIntroGraph() {
55354 var graph = this.graph();
55355 var baseEntities = {}; // clone base entities..
55357 Object.values(graph.base().entities).forEach(function (entity) {
55358 var copy = copyIntroEntity(entity);
55359 baseEntities[copy.id] = copy;
55360 }); // replace base entities with head entities..
55362 Object.keys(graph.entities).forEach(function (id) {
55363 var entity = graph.entities[id];
55366 var copy = copyIntroEntity(entity);
55367 baseEntities[copy.id] = copy;
55369 delete baseEntities[id];
55371 }); // swap temporary for permanent ids..
55373 Object.values(baseEntities).forEach(function (entity) {
55374 if (Array.isArray(entity.nodes)) {
55375 entity.nodes = entity.nodes.map(function (node) {
55376 return permIDs[node] || node;
55380 if (Array.isArray(entity.members)) {
55381 entity.members = entity.members.map(function (member) {
55382 member.id = permIDs[member.id] || member.id;
55387 return JSON.stringify({
55388 dataIntroGraph: baseEntities
55391 function copyIntroEntity(source) {
55392 var copy = utilObjectOmit(source, ['type', 'user', 'v', 'version', 'visible']); // Note: the copy is no longer an osmEntity, so it might not have `tags`
55394 if (copy.tags && !Object.keys(copy.tags)) {
55398 if (Array.isArray(copy.loc)) {
55399 copy.loc[0] = +copy.loc[0].toFixed(6);
55400 copy.loc[1] = +copy.loc[1].toFixed(6);
55403 var match = source.id.match(/([nrw])-\d*/); // temporary id
55405 if (match !== null) {
55406 var nrw = match[1];
55410 permID = nrw + ++nextID[nrw];
55411 } while (baseEntities.hasOwnProperty(permID));
55413 copy.id = permIDs[source.id] = permID;
55419 toJSON: function toJSON() {
55420 if (!this.hasChanges()) return;
55421 var allEntities = {};
55422 var baseEntities = {};
55423 var base = _stack[0];
55425 var s = _stack.map(function (i) {
55428 Object.keys(i.graph.entities).forEach(function (id) {
55429 var entity = i.graph.entities[id];
55432 var key = osmEntity.key(entity);
55433 allEntities[key] = entity;
55434 modified.push(key);
55437 } // make sure that the originals of changed or deleted entities get merged
55438 // into the base of the _stack after restoring the data from JSON.
55441 if (id in base.graph.entities) {
55442 baseEntities[id] = base.graph.entities[id];
55445 if (entity && entity.nodes) {
55446 // get originals of pre-existing child nodes
55447 entity.nodes.forEach(function (nodeID) {
55448 if (nodeID in base.graph.entities) {
55449 baseEntities[nodeID] = base.graph.entities[nodeID];
55452 } // get originals of parent entities too
55455 var baseParents = base.graph._parentWays[id];
55458 baseParents.forEach(function (parentID) {
55459 if (parentID in base.graph.entities) {
55460 baseEntities[parentID] = base.graph.entities[parentID];
55466 if (modified.length) x.modified = modified;
55467 if (deleted.length) x.deleted = deleted;
55468 if (i.imageryUsed) x.imageryUsed = i.imageryUsed;
55469 if (i.photoOverlaysUsed) x.photoOverlaysUsed = i.photoOverlaysUsed;
55470 if (i.annotation) x.annotation = i.annotation;
55471 if (i.transform) x.transform = i.transform;
55472 if (i.selectedIDs) x.selectedIDs = i.selectedIDs;
55476 return JSON.stringify({
55478 entities: Object.values(allEntities),
55479 baseEntities: Object.values(baseEntities),
55481 nextIDs: osmEntity.id.next,
55483 // note the time the changes were saved
55484 timestamp: new Date().getTime()
55487 fromJSON: function fromJSON(json, loadChildNodes) {
55488 var h = JSON.parse(json);
55489 var loadComplete = true;
55490 osmEntity.id.next = h.nextIDs;
55493 if (h.version === 2 || h.version === 3) {
55494 var allEntities = {};
55495 h.entities.forEach(function (entity) {
55496 allEntities[osmEntity.key(entity)] = osmEntity(entity);
55499 if (h.version === 3) {
55500 // This merges originals for changed entities into the base of
55501 // the _stack even if the current _stack doesn't have them (for
55502 // example when iD has been restarted in a different region)
55503 var baseEntities = h.baseEntities.map(function (d) {
55504 return osmEntity(d);
55507 var stack = _stack.map(function (state) {
55508 return state.graph;
55511 _stack[0].graph.rebase(baseEntities, stack, true);
55513 _tree.rebase(baseEntities, true); // When we restore a modified way, we also need to fetch any missing
55514 // childnodes that would normally have been downloaded with it.. #2142
55517 if (loadChildNodes) {
55518 var osm = context.connection();
55519 var baseWays = baseEntities.filter(function (e) {
55520 return e.type === 'way';
55522 var nodeIDs = baseWays.reduce(function (acc, way) {
55523 return utilArrayUnion(acc, way.nodes);
55525 var missing = nodeIDs.filter(function (n) {
55526 return !_stack[0].graph.hasEntity(n);
55529 if (missing.length && osm) {
55530 loadComplete = false;
55531 context.map().redrawEnable(false);
55532 var loading = uiLoading(context).blocking(true);
55533 context.container().call(loading);
55535 var childNodesLoaded = function childNodesLoaded(err, result) {
55537 var visibleGroups = utilArrayGroupBy(result.data, 'visible');
55538 var visibles = visibleGroups["true"] || []; // alive nodes
55540 var invisibles = visibleGroups["false"] || []; // deleted nodes
55542 if (visibles.length) {
55543 var visibleIDs = visibles.map(function (entity) {
55547 var stack = _stack.map(function (state) {
55548 return state.graph;
55551 missing = utilArrayDifference(missing, visibleIDs);
55553 _stack[0].graph.rebase(visibles, stack, true);
55555 _tree.rebase(visibles, true);
55556 } // fetch older versions of nodes that were deleted..
55559 invisibles.forEach(function (entity) {
55560 osm.loadEntityVersion(entity.id, +entity.version - 1, childNodesLoaded);
55564 if (err || !missing.length) {
55566 context.map().redrawEnable(true);
55567 dispatch.call('change');
55568 dispatch.call('restore', this);
55572 osm.loadMultiple(missing, childNodesLoaded);
55577 _stack = h.stack.map(function (d) {
55582 d.modified.forEach(function (key) {
55583 entity = allEntities[key];
55584 entities[entity.id] = entity;
55589 d.deleted.forEach(function (id) {
55590 entities[id] = undefined;
55595 graph: coreGraph(_stack[0].graph).load(entities),
55596 annotation: d.annotation,
55597 imageryUsed: d.imageryUsed,
55598 photoOverlaysUsed: d.photoOverlaysUsed,
55599 transform: d.transform,
55600 selectedIDs: d.selectedIDs
55604 // original version
55605 _stack = h.stack.map(function (d) {
55608 for (var i in d.entities) {
55609 var entity = d.entities[i];
55610 entities[i] = entity === 'undefined' ? undefined : osmEntity(entity);
55613 d.graph = coreGraph(_stack[0].graph).load(entities);
55618 var transform = _stack[_index].transform;
55621 context.map().transformEase(transform, 0); // 0 = immediate, no easing
55624 if (loadComplete) {
55625 dispatch.call('change');
55626 dispatch.call('restore', this);
55631 lock: function lock() {
55632 return _lock.lock();
55634 unlock: function unlock() {
55637 save: function save() {
55638 if (_lock.locked() && // don't overwrite existing, unresolved changes
55639 !_hasUnresolvedRestorableChanges) {
55640 var success = corePreferences(getKey('saved_history'), history.toJSON() || null);
55641 if (!success) dispatch.call('storage_error');
55646 // delete the history version saved in localStorage
55647 clearSaved: function clearSaved() {
55648 context.debouncedSave.cancel();
55650 if (_lock.locked()) {
55651 _hasUnresolvedRestorableChanges = false;
55652 corePreferences(getKey('saved_history'), null); // clear the changeset metadata associated with the saved history
55654 corePreferences('comment', null);
55655 corePreferences('hashtags', null);
55656 corePreferences('source', null);
55661 savedHistoryJSON: function savedHistoryJSON() {
55662 return corePreferences(getKey('saved_history'));
55664 hasRestorableChanges: function hasRestorableChanges() {
55665 return _hasUnresolvedRestorableChanges;
55667 // load history from a version stored in localStorage
55668 restore: function restore() {
55669 if (_lock.locked()) {
55670 _hasUnresolvedRestorableChanges = false;
55671 var json = this.savedHistoryJSON();
55672 if (json) history.fromJSON(json, true);
55678 return utilRebind(history, dispatch, 'on');
55682 * Look for roads that can be connected to other roads with a short extension
55685 function validationAlmostJunction(context) {
55686 var type = 'almost_junction';
55687 var EXTEND_TH_METERS = 5;
55688 var WELD_TH_METERS = 0.75; // Comes from considering bounding case of parallel ways
55690 var CLOSE_NODE_TH = EXTEND_TH_METERS - WELD_TH_METERS; // Comes from considering bounding case of perpendicular ways
55692 var SIG_ANGLE_TH = Math.atan(WELD_TH_METERS / EXTEND_TH_METERS);
55694 function isHighway(entity) {
55695 return entity.type === 'way' && osmRoutableHighwayTagValues[entity.tags.highway];
55698 function isTaggedAsNotContinuing(node) {
55699 return node.tags.noexit === 'yes' || node.tags.amenity === 'parking_entrance' || node.tags.entrance && node.tags.entrance !== 'no';
55702 var validation = function checkAlmostJunction(entity, graph) {
55703 if (!isHighway(entity)) return [];
55704 if (entity.isDegenerate()) return [];
55705 var tree = context.history().tree();
55706 var extendableNodeInfos = findConnectableEndNodesByExtension(entity);
55708 extendableNodeInfos.forEach(function (extendableNodeInfo) {
55709 issues.push(new validationIssue({
55711 subtype: 'highway-highway',
55712 severity: 'warning',
55713 message: function message(context) {
55714 var entity1 = context.hasEntity(this.entityIds[0]);
55716 if (this.entityIds[0] === this.entityIds[2]) {
55717 return entity1 ? _t.html('issues.almost_junction.self.message', {
55718 feature: utilDisplayLabel(entity1, context.graph())
55721 var entity2 = context.hasEntity(this.entityIds[2]);
55722 return entity1 && entity2 ? _t.html('issues.almost_junction.message', {
55723 feature: utilDisplayLabel(entity1, context.graph()),
55724 feature2: utilDisplayLabel(entity2, context.graph())
55728 reference: showReference,
55729 entityIds: [entity.id, extendableNodeInfo.node.id, extendableNodeInfo.wid],
55730 loc: extendableNodeInfo.node.loc,
55731 hash: JSON.stringify(extendableNodeInfo.node.loc),
55733 midId: extendableNodeInfo.mid.id,
55734 edge: extendableNodeInfo.edge,
55735 cross_loc: extendableNodeInfo.cross_loc
55737 dynamicFixes: makeFixes
55742 function makeFixes(context) {
55743 var fixes = [new validationIssueFix({
55744 icon: 'iD-icon-abutment',
55745 title: _t.html('issues.fix.connect_features.title'),
55746 onClick: function onClick(context) {
55747 var annotation = _t('issues.fix.connect_almost_junction.annotation');
55749 var _this$issue$entityIds = _slicedToArray(this.issue.entityIds, 3),
55750 endNodeId = _this$issue$entityIds[1],
55751 crossWayId = _this$issue$entityIds[2];
55753 var midNode = context.entity(this.issue.data.midId);
55754 var endNode = context.entity(endNodeId);
55755 var crossWay = context.entity(crossWayId); // When endpoints are close, just join if resulting small change in angle (#7201)
55757 var nearEndNodes = findNearbyEndNodes(endNode, crossWay);
55759 if (nearEndNodes.length > 0) {
55760 var collinear = findSmallJoinAngle(midNode, endNode, nearEndNodes);
55763 context.perform(actionMergeNodes([collinear.id, endNode.id], collinear.loc), annotation);
55768 var targetEdge = this.issue.data.edge;
55769 var crossLoc = this.issue.data.cross_loc;
55770 var edgeNodes = [context.entity(targetEdge[0]), context.entity(targetEdge[1])];
55771 var closestNodeInfo = geoSphericalClosestNode(edgeNodes, crossLoc); // already a point nearby, just connect to that
55773 if (closestNodeInfo.distance < WELD_TH_METERS) {
55774 context.perform(actionMergeNodes([closestNodeInfo.node.id, endNode.id], closestNodeInfo.node.loc), annotation); // else add the end node to the edge way
55776 context.perform(actionAddMidpoint({
55779 }, endNode), annotation);
55783 var node = context.hasEntity(this.entityIds[1]);
55785 if (node && !node.hasInterestingTags()) {
55786 // node has no descriptive tags, suggest noexit fix
55787 fixes.push(new validationIssueFix({
55788 icon: 'maki-barrier',
55789 title: _t.html('issues.fix.tag_as_disconnected.title'),
55790 onClick: function onClick(context) {
55791 var nodeID = this.issue.entityIds[1];
55792 var tags = Object.assign({}, context.entity(nodeID).tags);
55793 tags.noexit = 'yes';
55794 context.perform(actionChangeTags(nodeID, tags), _t('issues.fix.tag_as_disconnected.annotation'));
55802 function showReference(selection) {
55803 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.almost_junction.highway-highway.reference'));
55806 function isExtendableCandidate(node, way) {
55807 // can not accurately test vertices on tiles not downloaded from osm - #5938
55808 var osm = services.osm;
55810 if (osm && !osm.isDataLoaded(node.loc)) {
55814 if (isTaggedAsNotContinuing(node) || graph.parentWays(node).length !== 1) {
55818 var occurrences = 0;
55820 for (var index in way.nodes) {
55821 if (way.nodes[index] === node.id) {
55824 if (occurrences > 1) {
55833 function findConnectableEndNodesByExtension(way) {
55835 if (way.isClosed()) return results;
55837 var indices = [0, way.nodes.length - 1];
55838 indices.forEach(function (nodeIndex) {
55839 var nodeID = way.nodes[nodeIndex];
55840 var node = graph.entity(nodeID);
55841 if (!isExtendableCandidate(node, way)) return;
55842 var connectionInfo = canConnectByExtend(way, nodeIndex);
55843 if (!connectionInfo) return;
55844 testNodes = graph.childNodes(way).slice(); // shallow copy
55846 testNodes[nodeIndex] = testNodes[nodeIndex].move(connectionInfo.cross_loc); // don't flag issue if connecting the ways would cause self-intersection
55848 if (geoHasSelfIntersections(testNodes, nodeID)) return;
55849 results.push(connectionInfo);
55854 function findNearbyEndNodes(node, way) {
55855 return [way.nodes[0], way.nodes[way.nodes.length - 1]].map(function (d) {
55856 return graph.entity(d);
55857 }).filter(function (d) {
55858 // Node cannot be near to itself, but other endnode of same way could be
55859 return d.id !== node.id && geoSphericalDistance(node.loc, d.loc) <= CLOSE_NODE_TH;
55863 function findSmallJoinAngle(midNode, tipNode, endNodes) {
55864 // Both nodes could be close, so want to join whichever is closest to collinear
55866 var minAngle = Infinity; // Checks midNode -> tipNode -> endNode for collinearity
55868 endNodes.forEach(function (endNode) {
55869 var a1 = geoAngle(midNode, tipNode, context.projection) + Math.PI;
55870 var a2 = geoAngle(midNode, endNode, context.projection) + Math.PI;
55871 var diff = Math.max(a1, a2) - Math.min(a1, a2);
55873 if (diff < minAngle) {
55878 /* Threshold set by considering right angle triangle
55879 based on node joining threshold and extension distance */
55881 if (minAngle <= SIG_ANGLE_TH) return joinTo;
55885 function hasTag(tags, key) {
55886 return tags[key] !== undefined && tags[key] !== 'no';
55889 function canConnectWays(way, way2) {
55890 // allow self-connections
55891 if (way.id === way2.id) return true; // if one is bridge or tunnel, both must be bridge or tunnel
55893 if ((hasTag(way.tags, 'bridge') || hasTag(way2.tags, 'bridge')) && !(hasTag(way.tags, 'bridge') && hasTag(way2.tags, 'bridge'))) return false;
55894 if ((hasTag(way.tags, 'tunnel') || hasTag(way2.tags, 'tunnel')) && !(hasTag(way.tags, 'tunnel') && hasTag(way2.tags, 'tunnel'))) return false; // must have equivalent layers and levels
55896 var layer1 = way.tags.layer || '0',
55897 layer2 = way2.tags.layer || '0';
55898 if (layer1 !== layer2) return false;
55899 var level1 = way.tags.level || '0',
55900 level2 = way2.tags.level || '0';
55901 if (level1 !== level2) return false;
55905 function canConnectByExtend(way, endNodeIdx) {
55906 var tipNid = way.nodes[endNodeIdx]; // the 'tip' node for extension point
55908 var midNid = endNodeIdx === 0 ? way.nodes[1] : way.nodes[way.nodes.length - 2]; // the other node of the edge
55910 var tipNode = graph.entity(tipNid);
55911 var midNode = graph.entity(midNid);
55912 var lon = tipNode.loc[0];
55913 var lat = tipNode.loc[1];
55914 var lon_range = geoMetersToLon(EXTEND_TH_METERS, lat) / 2;
55915 var lat_range = geoMetersToLat(EXTEND_TH_METERS) / 2;
55916 var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]); // first, extend the edge of [midNode -> tipNode] by EXTEND_TH_METERS and find the "extended tip" location
55918 var edgeLen = geoSphericalDistance(midNode.loc, tipNode.loc);
55919 var t = EXTEND_TH_METERS / edgeLen + 1.0;
55920 var extTipLoc = geoVecInterp(midNode.loc, tipNode.loc, t); // then, check if the extension part [tipNode.loc -> extTipLoc] intersects any other ways
55922 var segmentInfos = tree.waySegments(queryExtent, graph);
55924 for (var i = 0; i < segmentInfos.length; i++) {
55925 var segmentInfo = segmentInfos[i];
55926 var way2 = graph.entity(segmentInfo.wayId);
55927 if (!isHighway(way2)) continue;
55928 if (!canConnectWays(way, way2)) continue;
55929 var nAid = segmentInfo.nodes[0],
55930 nBid = segmentInfo.nodes[1];
55931 if (nAid === tipNid || nBid === tipNid) continue;
55932 var nA = graph.entity(nAid),
55933 nB = graph.entity(nBid);
55934 var crossLoc = geoLineIntersection([tipNode.loc, extTipLoc], [nA.loc, nB.loc]);
55941 edge: [nA.id, nB.id],
55942 cross_loc: crossLoc
55951 validation.type = type;
55955 function validationCloseNodes(context) {
55956 var type = 'close_nodes';
55957 var pointThresholdMeters = 0.2;
55959 var validation = function validation(entity, graph) {
55960 if (entity.type === 'node') {
55961 return getIssuesForNode(entity);
55962 } else if (entity.type === 'way') {
55963 return getIssuesForWay(entity);
55968 function getIssuesForNode(node) {
55969 var parentWays = graph.parentWays(node);
55971 if (parentWays.length) {
55972 return getIssuesForVertex(node, parentWays);
55974 return getIssuesForDetachedPoint(node);
55978 function wayTypeFor(way) {
55979 if (way.tags.boundary && way.tags.boundary !== 'no') return 'boundary';
55980 if (way.tags.indoor && way.tags.indoor !== 'no') return 'indoor';
55981 if (way.tags.building && way.tags.building !== 'no' || way.tags['building:part'] && way.tags['building:part'] !== 'no') return 'building';
55982 if (osmPathHighwayTagValues[way.tags.highway]) return 'path';
55983 var parentRelations = graph.parentRelations(way);
55985 for (var i in parentRelations) {
55986 var relation = parentRelations[i];
55987 if (relation.tags.type === 'boundary') return 'boundary';
55989 if (relation.isMultipolygon()) {
55990 if (relation.tags.indoor && relation.tags.indoor !== 'no') return 'indoor';
55991 if (relation.tags.building && relation.tags.building !== 'no' || relation.tags['building:part'] && relation.tags['building:part'] !== 'no') return 'building';
55998 function shouldCheckWay(way) {
55999 // don't flag issues where merging would create degenerate ways
56000 if (way.nodes.length <= 2 || way.isClosed() && way.nodes.length <= 4) return false;
56001 var bbox = way.extent(graph).bbox();
56002 var hypotenuseMeters = geoSphericalDistance([bbox.minX, bbox.minY], [bbox.maxX, bbox.maxY]); // don't flag close nodes in very small ways
56004 if (hypotenuseMeters < 1.5) return false;
56008 function getIssuesForWay(way) {
56009 if (!shouldCheckWay(way)) return [];
56011 nodes = graph.childNodes(way);
56013 for (var i = 0; i < nodes.length - 1; i++) {
56014 var node1 = nodes[i];
56015 var node2 = nodes[i + 1];
56016 var issue = getWayIssueIfAny(node1, node2, way);
56017 if (issue) issues.push(issue);
56023 function getIssuesForVertex(node, parentWays) {
56026 function checkForCloseness(node1, node2, way) {
56027 var issue = getWayIssueIfAny(node1, node2, way);
56028 if (issue) issues.push(issue);
56031 for (var i = 0; i < parentWays.length; i++) {
56032 var parentWay = parentWays[i];
56033 if (!shouldCheckWay(parentWay)) continue;
56034 var lastIndex = parentWay.nodes.length - 1;
56036 for (var j = 0; j < parentWay.nodes.length; j++) {
56038 if (parentWay.nodes[j - 1] === node.id) {
56039 checkForCloseness(node, graph.entity(parentWay.nodes[j]), parentWay);
56043 if (j !== lastIndex) {
56044 if (parentWay.nodes[j + 1] === node.id) {
56045 checkForCloseness(graph.entity(parentWay.nodes[j]), node, parentWay);
56054 function thresholdMetersForWay(way) {
56055 if (!shouldCheckWay(way)) return 0;
56056 var wayType = wayTypeFor(way); // don't flag boundaries since they might be highly detailed and can't be easily verified
56058 if (wayType === 'boundary') return 0; // expect some features to be mapped with higher levels of detail
56060 if (wayType === 'indoor') return 0.01;
56061 if (wayType === 'building') return 0.05;
56062 if (wayType === 'path') return 0.1;
56066 function getIssuesForDetachedPoint(node) {
56068 var lon = node.loc[0];
56069 var lat = node.loc[1];
56070 var lon_range = geoMetersToLon(pointThresholdMeters, lat) / 2;
56071 var lat_range = geoMetersToLat(pointThresholdMeters) / 2;
56072 var queryExtent = geoExtent([[lon - lon_range, lat - lat_range], [lon + lon_range, lat + lat_range]]);
56073 var intersected = context.history().tree().intersects(queryExtent, graph);
56075 for (var j = 0; j < intersected.length; j++) {
56076 var nearby = intersected[j];
56077 if (nearby.id === node.id) continue;
56078 if (nearby.type !== 'node' || nearby.geometry(graph) !== 'point') continue;
56080 if (nearby.loc === node.loc || geoSphericalDistance(node.loc, nearby.loc) < pointThresholdMeters) {
56081 // allow very close points if tags indicate the z-axis might vary
56085 'addr:housenumber': true,
56088 var zAxisDifferentiates = false;
56090 for (var key in zAxisKeys) {
56091 var nodeValue = node.tags[key] || '0';
56092 var nearbyValue = nearby.tags[key] || '0';
56094 if (nodeValue !== nearbyValue) {
56095 zAxisDifferentiates = true;
56100 if (zAxisDifferentiates) continue;
56101 issues.push(new validationIssue({
56103 subtype: 'detached',
56104 severity: 'warning',
56105 message: function message(context) {
56106 var entity = context.hasEntity(this.entityIds[0]),
56107 entity2 = context.hasEntity(this.entityIds[1]);
56108 return entity && entity2 ? _t.html('issues.close_nodes.detached.message', {
56109 feature: utilDisplayLabel(entity, context.graph()),
56110 feature2: utilDisplayLabel(entity2, context.graph())
56113 reference: showReference,
56114 entityIds: [node.id, nearby.id],
56115 dynamicFixes: function dynamicFixes() {
56116 return [new validationIssueFix({
56117 icon: 'iD-operation-disconnect',
56118 title: _t.html('issues.fix.move_points_apart.title')
56119 }), new validationIssueFix({
56120 icon: 'iD-icon-layers',
56121 title: _t.html('issues.fix.use_different_layers_or_levels.title')
56130 function showReference(selection) {
56131 var referenceText = _t('issues.close_nodes.detached.reference');
56132 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
56136 function getWayIssueIfAny(node1, node2, way) {
56137 if (node1.id === node2.id || node1.hasInterestingTags() && node2.hasInterestingTags()) {
56141 if (node1.loc !== node2.loc) {
56142 var parentWays1 = graph.parentWays(node1);
56143 var parentWays2 = new Set(graph.parentWays(node2));
56144 var sharedWays = parentWays1.filter(function (parentWay) {
56145 return parentWays2.has(parentWay);
56147 var thresholds = sharedWays.map(function (parentWay) {
56148 return thresholdMetersForWay(parentWay);
56150 var threshold = Math.min.apply(Math, _toConsumableArray(thresholds));
56151 var distance = geoSphericalDistance(node1.loc, node2.loc);
56152 if (distance > threshold) return null;
56155 return new validationIssue({
56157 subtype: 'vertices',
56158 severity: 'warning',
56159 message: function message(context) {
56160 var entity = context.hasEntity(this.entityIds[0]);
56161 return entity ? _t.html('issues.close_nodes.message', {
56162 way: utilDisplayLabel(entity, context.graph())
56165 reference: showReference,
56166 entityIds: [way.id, node1.id, node2.id],
56168 dynamicFixes: function dynamicFixes() {
56169 return [new validationIssueFix({
56170 icon: 'iD-icon-plus',
56171 title: _t.html('issues.fix.merge_points.title'),
56172 onClick: function onClick(context) {
56173 var entityIds = this.issue.entityIds;
56174 var action = actionMergeNodes([entityIds[1], entityIds[2]]);
56175 context.perform(action, _t('issues.fix.merge_close_vertices.annotation'));
56177 }), new validationIssueFix({
56178 icon: 'iD-operation-disconnect',
56179 title: _t.html('issues.fix.move_points_apart.title')
56184 function showReference(selection) {
56185 var referenceText = _t('issues.close_nodes.reference');
56186 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(referenceText);
56191 validation.type = type;
56195 function validationCrossingWays(context) {
56196 var type = 'crossing_ways'; // returns the way or its parent relation, whichever has a useful feature type
56198 function getFeatureWithFeatureTypeTagsForWay(way, graph) {
56199 if (getFeatureType(way, graph) === null) {
56200 // if the way doesn't match a feature type, check its parent relations
56201 var parentRels = graph.parentRelations(way);
56203 for (var i = 0; i < parentRels.length; i++) {
56204 var rel = parentRels[i];
56206 if (getFeatureType(rel, graph) !== null) {
56215 function hasTag(tags, key) {
56216 return tags[key] !== undefined && tags[key] !== 'no';
56219 function taggedAsIndoor(tags) {
56220 return hasTag(tags, 'indoor') || hasTag(tags, 'level') || tags.highway === 'corridor';
56223 function allowsBridge(featureType) {
56224 return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
56227 function allowsTunnel(featureType) {
56228 return featureType === 'highway' || featureType === 'railway' || featureType === 'waterway';
56232 var ignoredBuildings = {
56239 function getFeatureType(entity, graph) {
56240 var geometry = entity.geometry(graph);
56241 if (geometry !== 'line' && geometry !== 'area') return null;
56242 var tags = entity.tags;
56243 if (hasTag(tags, 'building') && !ignoredBuildings[tags.building]) return 'building';
56244 if (hasTag(tags, 'highway') && osmRoutableHighwayTagValues[tags.highway]) return 'highway'; // don't check railway or waterway areas
56246 if (geometry !== 'line') return null;
56247 if (hasTag(tags, 'railway') && osmRailwayTrackTagValues[tags.railway]) return 'railway';
56248 if (hasTag(tags, 'waterway') && osmFlowingWaterwayTagValues[tags.waterway]) return 'waterway';
56252 function isLegitCrossing(tags1, featureType1, tags2, featureType2) {
56253 // assume 0 by default
56254 var level1 = tags1.level || '0';
56255 var level2 = tags2.level || '0';
56257 if (taggedAsIndoor(tags1) && taggedAsIndoor(tags2) && level1 !== level2) {
56258 // assume features don't interact if they're indoor on different levels
56260 } // assume 0 by default; don't use way.layer() since we account for structures here
56263 var layer1 = tags1.layer || '0';
56264 var layer2 = tags2.layer || '0';
56266 if (allowsBridge(featureType1) && allowsBridge(featureType2)) {
56267 if (hasTag(tags1, 'bridge') && !hasTag(tags2, 'bridge')) return true;
56268 if (!hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge')) return true; // crossing bridges must use different layers
56270 if (hasTag(tags1, 'bridge') && hasTag(tags2, 'bridge') && layer1 !== layer2) return true;
56271 } else if (allowsBridge(featureType1) && hasTag(tags1, 'bridge')) return true;else if (allowsBridge(featureType2) && hasTag(tags2, 'bridge')) return true;
56273 if (allowsTunnel(featureType1) && allowsTunnel(featureType2)) {
56274 if (hasTag(tags1, 'tunnel') && !hasTag(tags2, 'tunnel')) return true;
56275 if (!hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel')) return true; // crossing tunnels must use different layers
56277 if (hasTag(tags1, 'tunnel') && hasTag(tags2, 'tunnel') && layer1 !== layer2) return true;
56278 } else if (allowsTunnel(featureType1) && hasTag(tags1, 'tunnel')) return true;else if (allowsTunnel(featureType2) && hasTag(tags2, 'tunnel')) return true; // don't flag crossing waterways and pier/highways
56281 if (featureType1 === 'waterway' && featureType2 === 'highway' && tags2.man_made === 'pier') return true;
56282 if (featureType2 === 'waterway' && featureType1 === 'highway' && tags1.man_made === 'pier') return true;
56284 if (featureType1 === 'building' || featureType2 === 'building') {
56285 // for building crossings, different layers are enough
56286 if (layer1 !== layer2) return true;
56290 } // highway values for which we shouldn't recommend connecting to waterways
56293 var highwaysDisallowingFords = {
56295 motorway_link: true,
56299 primary_link: true,
56301 secondary_link: true
56303 var nonCrossingHighways = {
56307 function tagsForConnectionNodeIfAllowed(entity1, entity2, graph) {
56308 var featureType1 = getFeatureType(entity1, graph);
56309 var featureType2 = getFeatureType(entity2, graph);
56310 var geometry1 = entity1.geometry(graph);
56311 var geometry2 = entity2.geometry(graph);
56312 var bothLines = geometry1 === 'line' && geometry2 === 'line';
56314 if (featureType1 === featureType2) {
56315 if (featureType1 === 'highway') {
56316 var entity1IsPath = osmPathHighwayTagValues[entity1.tags.highway];
56317 var entity2IsPath = osmPathHighwayTagValues[entity2.tags.highway];
56319 if ((entity1IsPath || entity2IsPath) && entity1IsPath !== entity2IsPath) {
56320 // one feature is a path but not both
56321 var roadFeature = entity1IsPath ? entity2 : entity1;
56323 if (nonCrossingHighways[roadFeature.tags.highway]) {
56324 // don't mark path connections with certain roads as crossings
56328 var pathFeature = entity1IsPath ? entity1 : entity2;
56330 if (['marked', 'unmarked'].indexOf(pathFeature.tags.crossing) !== -1) {
56331 // if the path is a crossing, match the crossing type
56332 return bothLines ? {
56333 highway: 'crossing',
56334 crossing: pathFeature.tags.crossing
56336 } // don't add a `crossing` subtag to ambiguous crossings
56339 return bothLines ? {
56340 highway: 'crossing'
56347 if (featureType1 === 'waterway') return {};
56348 if (featureType1 === 'railway') return {};
56350 var featureTypes = [featureType1, featureType2];
56352 if (featureTypes.indexOf('highway') !== -1) {
56353 if (featureTypes.indexOf('railway') !== -1) {
56354 if (!bothLines) return {};
56355 var isTram = entity1.tags.railway === 'tram' || entity2.tags.railway === 'tram';
56357 if (osmPathHighwayTagValues[entity1.tags.highway] || osmPathHighwayTagValues[entity2.tags.highway]) {
56358 // path-tram connections use this tag
56359 if (isTram) return {
56360 railway: 'tram_crossing'
56361 }; // other path-rail connections use this tag
56364 railway: 'crossing'
56367 // path-tram connections use this tag
56368 if (isTram) return {
56369 railway: 'tram_level_crossing'
56370 }; // other road-rail connections use this tag
56373 railway: 'level_crossing'
56378 if (featureTypes.indexOf('waterway') !== -1) {
56379 // do not allow fords on structures
56380 if (hasTag(entity1.tags, 'tunnel') && hasTag(entity2.tags, 'tunnel')) return null;
56381 if (hasTag(entity1.tags, 'bridge') && hasTag(entity2.tags, 'bridge')) return null;
56383 if (highwaysDisallowingFords[entity1.tags.highway] || highwaysDisallowingFords[entity2.tags.highway]) {
56384 // do not allow fords on major highways
56388 return bothLines ? {
56398 function findCrossingsByWay(way1, graph, tree) {
56399 var edgeCrossInfos = [];
56400 if (way1.type !== 'way') return edgeCrossInfos;
56401 var taggedFeature1 = getFeatureWithFeatureTypeTagsForWay(way1, graph);
56402 var way1FeatureType = getFeatureType(taggedFeature1, graph);
56403 if (way1FeatureType === null) return edgeCrossInfos;
56404 var checkedSingleCrossingWays = {}; // declare vars ahead of time to reduce garbage collection
56408 var n1, n2, nA, nB, nAId, nBId;
56409 var segment1, segment2;
56411 var segmentInfos, segment2Info, way2, taggedFeature2, way2FeatureType;
56412 var way1Nodes = graph.childNodes(way1);
56413 var comparedWays = {};
56415 for (i = 0; i < way1Nodes.length - 1; i++) {
56417 n2 = way1Nodes[i + 1];
56418 extent = geoExtent([[Math.min(n1.loc[0], n2.loc[0]), Math.min(n1.loc[1], n2.loc[1])], [Math.max(n1.loc[0], n2.loc[0]), Math.max(n1.loc[1], n2.loc[1])]]); // Optimize by only checking overlapping segments, not every segment
56419 // of overlapping ways
56421 segmentInfos = tree.waySegments(extent, graph);
56423 for (j = 0; j < segmentInfos.length; j++) {
56424 segment2Info = segmentInfos[j]; // don't check for self-intersection in this validation
56426 if (segment2Info.wayId === way1.id) continue; // skip if this way was already checked and only one issue is needed
56428 if (checkedSingleCrossingWays[segment2Info.wayId]) continue; // mark this way as checked even if there are no crossings
56430 comparedWays[segment2Info.wayId] = true;
56431 way2 = graph.hasEntity(segment2Info.wayId);
56432 if (!way2) continue;
56433 taggedFeature2 = getFeatureWithFeatureTypeTagsForWay(way2, graph); // only check crossing highway, waterway, building, and railway
56435 way2FeatureType = getFeatureType(taggedFeature2, graph);
56437 if (way2FeatureType === null || isLegitCrossing(taggedFeature1.tags, way1FeatureType, taggedFeature2.tags, way2FeatureType)) {
56439 } // create only one issue for building crossings
56442 oneOnly = way1FeatureType === 'building' || way2FeatureType === 'building';
56443 nAId = segment2Info.nodes[0];
56444 nBId = segment2Info.nodes[1];
56446 if (nAId === n1.id || nAId === n2.id || nBId === n1.id || nBId === n2.id) {
56447 // n1 or n2 is a connection node; skip
56451 nA = graph.hasEntity(nAId);
56453 nB = graph.hasEntity(nBId);
56455 segment1 = [n1.loc, n2.loc];
56456 segment2 = [nA.loc, nB.loc];
56457 var point = geoLineIntersection(segment1, segment2);
56460 edgeCrossInfos.push({
56463 featureType: way1FeatureType,
56464 edge: [n1.id, n2.id]
56467 featureType: way2FeatureType,
56468 edge: [nA.id, nB.id]
56474 checkedSingleCrossingWays[way2.id] = true;
56481 return edgeCrossInfos;
56484 function waysToCheck(entity, graph) {
56485 var featureType = getFeatureType(entity, graph);
56486 if (!featureType) return [];
56488 if (entity.type === 'way') {
56490 } else if (entity.type === 'relation') {
56491 return entity.members.reduce(function (array, member) {
56492 if (member.type === 'way' && ( // only look at geometry ways
56493 !member.role || member.role === 'outer' || member.role === 'inner')) {
56494 var entity = graph.hasEntity(member.id); // don't add duplicates
56496 if (entity && array.indexOf(entity) === -1) {
56497 array.push(entity);
56508 var validation = function checkCrossingWays(entity, graph) {
56509 var tree = context.history().tree();
56510 var ways = waysToCheck(entity, graph);
56511 var issues = []; // declare these here to reduce garbage collection
56513 var wayIndex, crossingIndex, crossings;
56515 for (wayIndex in ways) {
56516 crossings = findCrossingsByWay(ways[wayIndex], graph, tree);
56518 for (crossingIndex in crossings) {
56519 issues.push(createIssue(crossings[crossingIndex], graph));
56526 function createIssue(crossing, graph) {
56527 // use the entities with the tags that define the feature type
56528 crossing.wayInfos.sort(function (way1Info, way2Info) {
56529 var type1 = way1Info.featureType;
56530 var type2 = way2Info.featureType;
56532 if (type1 === type2) {
56533 return utilDisplayLabel(way1Info.way, graph) > utilDisplayLabel(way2Info.way, graph);
56534 } else if (type1 === 'waterway') {
56536 } else if (type2 === 'waterway') {
56540 return type1 < type2;
56542 var entities = crossing.wayInfos.map(function (wayInfo) {
56543 return getFeatureWithFeatureTypeTagsForWay(wayInfo.way, graph);
56545 var edges = [crossing.wayInfos[0].edge, crossing.wayInfos[1].edge];
56546 var featureTypes = [crossing.wayInfos[0].featureType, crossing.wayInfos[1].featureType];
56547 var connectionTags = tagsForConnectionNodeIfAllowed(entities[0], entities[1], graph);
56548 var featureType1 = crossing.wayInfos[0].featureType;
56549 var featureType2 = crossing.wayInfos[1].featureType;
56550 var isCrossingIndoors = taggedAsIndoor(entities[0].tags) && taggedAsIndoor(entities[1].tags);
56551 var isCrossingTunnels = allowsTunnel(featureType1) && hasTag(entities[0].tags, 'tunnel') && allowsTunnel(featureType2) && hasTag(entities[1].tags, 'tunnel');
56552 var isCrossingBridges = allowsBridge(featureType1) && hasTag(entities[0].tags, 'bridge') && allowsBridge(featureType2) && hasTag(entities[1].tags, 'bridge');
56553 var subtype = [featureType1, featureType2].sort().join('-');
56554 var crossingTypeID = subtype;
56556 if (isCrossingIndoors) {
56557 crossingTypeID = 'indoor-indoor';
56558 } else if (isCrossingTunnels) {
56559 crossingTypeID = 'tunnel-tunnel';
56560 } else if (isCrossingBridges) {
56561 crossingTypeID = 'bridge-bridge';
56564 if (connectionTags && (isCrossingIndoors || isCrossingTunnels || isCrossingBridges)) {
56565 crossingTypeID += '_connectable';
56566 } // Differentiate based on the loc rounded to 4 digits, since two ways can cross multiple times.
56569 var uniqueID = '' + crossing.crossPoint[0].toFixed(4) + ',' + crossing.crossPoint[1].toFixed(4);
56570 return new validationIssue({
56573 severity: 'warning',
56574 message: function message(context) {
56575 var graph = context.graph();
56576 var entity1 = graph.hasEntity(this.entityIds[0]),
56577 entity2 = graph.hasEntity(this.entityIds[1]);
56578 return entity1 && entity2 ? _t.html('issues.crossing_ways.message', {
56579 feature: utilDisplayLabel(entity1, graph),
56580 feature2: utilDisplayLabel(entity2, graph)
56583 reference: showReference,
56584 entityIds: entities.map(function (entity) {
56589 featureTypes: featureTypes,
56590 connectionTags: connectionTags
56593 loc: crossing.crossPoint,
56594 dynamicFixes: function dynamicFixes(context) {
56595 var mode = context.mode();
56596 if (!mode || mode.id !== 'select' || mode.selectedIDs().length !== 1) return [];
56597 var selectedIndex = this.entityIds[0] === mode.selectedIDs()[0] ? 0 : 1;
56598 var selectedFeatureType = this.data.featureTypes[selectedIndex];
56599 var otherFeatureType = this.data.featureTypes[selectedIndex === 0 ? 1 : 0];
56602 if (connectionTags) {
56603 fixes.push(makeConnectWaysFix(this.data.connectionTags));
56606 if (isCrossingIndoors) {
56607 fixes.push(new validationIssueFix({
56608 icon: 'iD-icon-layers',
56609 title: _t.html('issues.fix.use_different_levels.title')
56611 } else if (isCrossingTunnels || isCrossingBridges || featureType1 === 'building' || featureType2 === 'building') {
56612 fixes.push(makeChangeLayerFix('higher'));
56613 fixes.push(makeChangeLayerFix('lower')); // can only add bridge/tunnel if both features are lines
56614 } else if (context.graph().geometry(this.entityIds[0]) === 'line' && context.graph().geometry(this.entityIds[1]) === 'line') {
56615 // don't recommend adding bridges to waterways since they're uncommon
56616 if (allowsBridge(selectedFeatureType) && selectedFeatureType !== 'waterway') {
56617 fixes.push(makeAddBridgeOrTunnelFix('add_a_bridge', 'temaki-bridge', 'bridge'));
56618 } // don't recommend adding tunnels under waterways since they're uncommon
56621 var skipTunnelFix = otherFeatureType === 'waterway' && selectedFeatureType !== 'waterway';
56623 if (allowsTunnel(selectedFeatureType) && !skipTunnelFix) {
56624 fixes.push(makeAddBridgeOrTunnelFix('add_a_tunnel', 'temaki-tunnel', 'tunnel'));
56626 } // repositioning the features is always an option
56629 fixes.push(new validationIssueFix({
56630 icon: 'iD-operation-move',
56631 title: _t.html('issues.fix.reposition_features.title')
56637 function showReference(selection) {
56638 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.crossing_ways.' + crossingTypeID + '.reference'));
56642 function makeAddBridgeOrTunnelFix(fixTitleID, iconName, bridgeOrTunnel) {
56643 return new validationIssueFix({
56645 title: _t.html('issues.fix.' + fixTitleID + '.title'),
56646 onClick: function onClick(context) {
56647 var mode = context.mode();
56648 if (!mode || mode.id !== 'select') return;
56649 var selectedIDs = mode.selectedIDs();
56650 if (selectedIDs.length !== 1) return;
56651 var selectedWayID = selectedIDs[0];
56652 if (!context.hasEntity(selectedWayID)) return;
56653 var resultWayIDs = [selectedWayID];
56654 var edge, crossedEdge, crossedWayID;
56656 if (this.issue.entityIds[0] === selectedWayID) {
56657 edge = this.issue.data.edges[0];
56658 crossedEdge = this.issue.data.edges[1];
56659 crossedWayID = this.issue.entityIds[1];
56661 edge = this.issue.data.edges[1];
56662 crossedEdge = this.issue.data.edges[0];
56663 crossedWayID = this.issue.entityIds[0];
56666 var crossingLoc = this.issue.loc;
56667 var projection = context.projection;
56669 var action = function actionAddStructure(graph) {
56670 var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
56671 var crossedWay = graph.hasEntity(crossedWayID); // use the explicit width of the crossed feature as the structure length, if available
56673 var structLengthMeters = crossedWay && crossedWay.tags.width && parseFloat(crossedWay.tags.width);
56675 if (!structLengthMeters) {
56676 // if no explicit width is set, approximate the width based on the tags
56677 structLengthMeters = crossedWay && crossedWay.impliedLineWidthMeters();
56680 if (structLengthMeters) {
56681 if (getFeatureType(crossedWay, graph) === 'railway') {
56682 // bridges over railways are generally much longer than the rail bed itself, compensate
56683 structLengthMeters *= 2;
56686 // should ideally never land here since all rail/water/road tags should have an implied width
56687 structLengthMeters = 8;
56690 var a1 = geoAngle(edgeNodes[0], edgeNodes[1], projection) + Math.PI;
56691 var a2 = geoAngle(graph.entity(crossedEdge[0]), graph.entity(crossedEdge[1]), projection) + Math.PI;
56692 var crossingAngle = Math.max(a1, a2) - Math.min(a1, a2);
56693 if (crossingAngle > Math.PI) crossingAngle -= Math.PI; // lengthen the structure to account for the angle of the crossing
56695 structLengthMeters = structLengthMeters / 2 / Math.sin(crossingAngle) * 2; // add padding since the structure must extend past the edges of the crossed feature
56697 structLengthMeters += 4; // clamp the length to a reasonable range
56699 structLengthMeters = Math.min(Math.max(structLengthMeters, 4), 50);
56701 function geomToProj(geoPoint) {
56702 return [geoLonToMeters(geoPoint[0], geoPoint[1]), geoLatToMeters(geoPoint[1])];
56705 function projToGeom(projPoint) {
56706 var lat = geoMetersToLat(projPoint[1]);
56707 return [geoMetersToLon(projPoint[0], lat), lat];
56710 var projEdgeNode1 = geomToProj(edgeNodes[0].loc);
56711 var projEdgeNode2 = geomToProj(edgeNodes[1].loc);
56712 var projectedAngle = geoVecAngle(projEdgeNode1, projEdgeNode2);
56713 var projectedCrossingLoc = geomToProj(crossingLoc);
56714 var linearToSphericalMetersRatio = geoVecLength(projEdgeNode1, projEdgeNode2) / geoSphericalDistance(edgeNodes[0].loc, edgeNodes[1].loc);
56716 function locSphericalDistanceFromCrossingLoc(angle, distanceMeters) {
56717 var lengthSphericalMeters = distanceMeters * linearToSphericalMetersRatio;
56718 return projToGeom([projectedCrossingLoc[0] + Math.cos(angle) * lengthSphericalMeters, projectedCrossingLoc[1] + Math.sin(angle) * lengthSphericalMeters]);
56721 var endpointLocGetter1 = function endpointLocGetter1(lengthMeters) {
56722 return locSphericalDistanceFromCrossingLoc(projectedAngle, lengthMeters);
56725 var endpointLocGetter2 = function endpointLocGetter2(lengthMeters) {
56726 return locSphericalDistanceFromCrossingLoc(projectedAngle + Math.PI, lengthMeters);
56727 }; // avoid creating very short edges from splitting too close to another node
56730 var minEdgeLengthMeters = 0.55; // decide where to bound the structure along the way, splitting as necessary
56732 function determineEndpoint(edge, endNode, locGetter) {
56734 var idealLengthMeters = structLengthMeters / 2; // distance between the crossing location and the end of the edge,
56735 // the maximum length of this side of the structure
56737 var crossingToEdgeEndDistance = geoSphericalDistance(crossingLoc, endNode.loc);
56739 if (crossingToEdgeEndDistance - idealLengthMeters > minEdgeLengthMeters) {
56740 // the edge is long enough to insert a new node
56741 // the loc that would result in the full expected length
56742 var idealNodeLoc = locGetter(idealLengthMeters);
56743 newNode = osmNode();
56744 graph = actionAddMidpoint({
56747 }, newNode)(graph);
56750 endNode.parentIntersectionWays(graph).forEach(function (way) {
56751 way.nodes.forEach(function (nodeID) {
56752 if (nodeID === endNode.id) {
56753 if (endNode.id === way.first() && endNode.id !== way.last() || endNode.id === way.last() && endNode.id !== way.first()) {
56762 if (edgeCount >= 3) {
56763 // the end node is a junction, try to leave a segment
56764 // between it and the structure - #7202
56765 var insetLength = crossingToEdgeEndDistance - minEdgeLengthMeters;
56767 if (insetLength > minEdgeLengthMeters) {
56768 var insetNodeLoc = locGetter(insetLength);
56769 newNode = osmNode();
56770 graph = actionAddMidpoint({
56773 }, newNode)(graph);
56776 } // if the edge is too short to subdivide as desired, then
56777 // just bound the structure at the existing end node
56780 if (!newNode) newNode = endNode;
56781 var splitAction = actionSplit([newNode.id]).limitWays(resultWayIDs); // only split selected or created ways
56784 graph = splitAction(graph);
56786 if (splitAction.getCreatedWayIDs().length) {
56787 resultWayIDs.push(splitAction.getCreatedWayIDs()[0]);
56793 var structEndNode1 = determineEndpoint(edge, edgeNodes[1], endpointLocGetter1);
56794 var structEndNode2 = determineEndpoint([edgeNodes[0].id, structEndNode1.id], edgeNodes[0], endpointLocGetter2);
56795 var structureWay = resultWayIDs.map(function (id) {
56796 return graph.entity(id);
56797 }).find(function (way) {
56798 return way.nodes.indexOf(structEndNode1.id) !== -1 && way.nodes.indexOf(structEndNode2.id) !== -1;
56800 var tags = Object.assign({}, structureWay.tags); // copy tags
56802 if (bridgeOrTunnel === 'bridge') {
56803 tags.bridge = 'yes';
56806 var tunnelValue = 'yes';
56808 if (getFeatureType(structureWay, graph) === 'waterway') {
56809 // use `tunnel=culvert` for waterways by default
56810 tunnelValue = 'culvert';
56813 tags.tunnel = tunnelValue;
56815 } // apply the structure tags to the way
56818 graph = actionChangeTags(structureWay.id, tags)(graph);
56822 context.perform(action, _t('issues.fix.' + fixTitleID + '.annotation'));
56823 context.enter(modeSelect(context, resultWayIDs));
56828 function makeConnectWaysFix(connectionTags) {
56829 var fixTitleID = 'connect_features';
56831 if (connectionTags.ford) {
56832 fixTitleID = 'connect_using_ford';
56835 return new validationIssueFix({
56836 icon: 'iD-icon-crossing',
56837 title: _t.html('issues.fix.' + fixTitleID + '.title'),
56838 onClick: function onClick(context) {
56839 var loc = this.issue.loc;
56840 var connectionTags = this.issue.data.connectionTags;
56841 var edges = this.issue.data.edges;
56842 context.perform(function actionConnectCrossingWays(graph) {
56843 // create the new node for the points
56844 var node = osmNode({
56846 tags: connectionTags
56848 graph = graph.replace(node);
56849 var nodesToMerge = [node.id];
56850 var mergeThresholdInMeters = 0.75;
56851 edges.forEach(function (edge) {
56852 var edgeNodes = [graph.entity(edge[0]), graph.entity(edge[1])];
56853 var nearby = geoSphericalClosestNode(edgeNodes, loc); // if there is already a suitable node nearby, use that
56854 // use the node if node has no interesting tags or if it is a crossing node #8326
56856 if ((!nearby.node.hasInterestingTags() || nearby.node.isCrossing()) && nearby.distance < mergeThresholdInMeters) {
56857 nodesToMerge.push(nearby.node.id); // else add the new node to the way
56859 graph = actionAddMidpoint({
56866 if (nodesToMerge.length > 1) {
56867 // if we're using nearby nodes, merge them with the new node
56868 graph = actionMergeNodes(nodesToMerge, loc)(graph);
56872 }, _t('issues.fix.connect_crossing_features.annotation'));
56877 function makeChangeLayerFix(higherOrLower) {
56878 return new validationIssueFix({
56879 icon: 'iD-icon-' + (higherOrLower === 'higher' ? 'up' : 'down'),
56880 title: _t.html('issues.fix.tag_this_as_' + higherOrLower + '.title'),
56881 onClick: function onClick(context) {
56882 var mode = context.mode();
56883 if (!mode || mode.id !== 'select') return;
56884 var selectedIDs = mode.selectedIDs();
56885 if (selectedIDs.length !== 1) return;
56886 var selectedID = selectedIDs[0];
56887 if (!this.issue.entityIds.some(function (entityId) {
56888 return entityId === selectedID;
56890 var entity = context.hasEntity(selectedID);
56891 if (!entity) return;
56892 var tags = Object.assign({}, entity.tags); // shallow copy
56894 var layer = tags.layer && Number(tags.layer);
56896 if (layer && !isNaN(layer)) {
56897 if (higherOrLower === 'higher') {
56903 if (higherOrLower === 'higher') {
56910 tags.layer = layer.toString();
56911 context.perform(actionChangeTags(entity.id, tags), _t('operations.change_tags.annotation'));
56916 validation.type = type;
56920 function behaviorDrawWay(context, wayID, mode, startGraph) {
56921 var keybinding = utilKeybinding('drawWay');
56922 var dispatch = dispatch$8('rejectedSelfIntersection');
56923 var behavior = behaviorDraw(context); // Must be set by `drawWay.nodeIndex` before each install of this behavior.
56935 var _pointerHasMoved = false; // The osmNode to be placed.
56936 // This is temporary and just follows the mouse cursor until an "add" event occurs.
56940 var _didResolveTempEdit = false;
56942 function createDrawNode(loc) {
56943 // don't make the draw node until we actually need it
56944 _drawNode = osmNode({
56947 context.pauseChangeDispatch();
56948 context.replace(function actionAddDrawNode(graph) {
56949 // add the draw node to the graph and insert it into the way
56950 var way = graph.entity(wayID);
56951 return graph.replace(_drawNode).replace(way.addNode(_drawNode.id, _nodeIndex));
56953 context.resumeChangeDispatch();
56954 setActiveElements();
56957 function removeDrawNode() {
56958 context.pauseChangeDispatch();
56959 context.replace(function actionDeleteDrawNode(graph) {
56960 var way = graph.entity(wayID);
56961 return graph.replace(way.removeNode(_drawNode.id)).remove(_drawNode);
56963 _drawNode = undefined;
56964 context.resumeChangeDispatch();
56967 function keydown(d3_event) {
56968 if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56969 if (context.surface().classed('nope')) {
56970 context.surface().classed('nope-suppressed', true);
56973 context.surface().classed('nope', false).classed('nope-disabled', true);
56977 function keyup(d3_event) {
56978 if (d3_event.keyCode === utilKeybinding.modifierCodes.alt) {
56979 if (context.surface().classed('nope-suppressed')) {
56980 context.surface().classed('nope', true);
56983 context.surface().classed('nope-suppressed', false).classed('nope-disabled', false);
56987 function allowsVertex(d) {
56988 return d.geometry(context.graph()) === 'vertex' || _mainPresetIndex.allowsVertex(d, context.graph());
56990 // - `mode/drag_node.js` `doMove()`
56991 // - `behavior/draw.js` `click()`
56992 // - `behavior/draw_way.js` `move()`
56995 function move(d3_event, datum) {
56996 var loc = context.map().mouseCoordinates();
56997 if (!_drawNode) createDrawNode(loc);
56998 context.surface().classed('nope-disabled', d3_event.altKey);
56999 var targetLoc = datum && datum.properties && datum.properties.entity && allowsVertex(datum.properties.entity) && datum.properties.entity.loc;
57000 var targetNodes = datum && datum.properties && datum.properties.nodes;
57003 // snap to node/vertex - a point target with `.loc`
57005 } else if (targetNodes) {
57006 // snap to way - a line target with `.nodes`
57007 var choice = geoChooseEdge(targetNodes, context.map().mouse(), context.projection, _drawNode.id);
57014 context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
57015 _drawNode = context.entity(_drawNode.id);
57017 /* includeDrawNode */
57019 } // Check whether this edit causes the geometry to break.
57020 // If so, class the surface with a nope cursor.
57021 // `includeDrawNode` - Only check the relevant line segments if finishing drawing
57024 function checkGeometry(includeDrawNode) {
57025 var nopeDisabled = context.surface().classed('nope-disabled');
57026 var isInvalid = isInvalidGeometry(includeDrawNode);
57028 if (nopeDisabled) {
57029 context.surface().classed('nope', false).classed('nope-suppressed', isInvalid);
57031 context.surface().classed('nope', isInvalid).classed('nope-suppressed', false);
57035 function isInvalidGeometry(includeDrawNode) {
57036 var testNode = _drawNode; // we only need to test the single way we're drawing
57038 var parentWay = context.graph().entity(wayID);
57039 var nodes = context.graph().childNodes(parentWay).slice(); // shallow copy
57041 if (includeDrawNode) {
57042 if (parentWay.isClosed()) {
57043 // don't test the last segment for closed ways - #4655
57044 // (still test the first segment)
57048 // discount the draw node
57049 if (parentWay.isClosed()) {
57050 if (nodes.length < 3) return false;
57051 if (_drawNode) nodes.splice(-2, 1);
57052 testNode = nodes[nodes.length - 2];
57054 // there's nothing we need to test if we ignore the draw node on open ways
57059 return testNode && geoHasSelfIntersections(nodes, testNode.id);
57062 function undone() {
57063 // undoing removed the temp edit
57064 _didResolveTempEdit = true;
57065 context.pauseChangeDispatch();
57068 if (context.graph() === startGraph) {
57069 // We've undone back to the initial state before we started drawing.
57070 // Just exit the draw mode without undoing whatever we did before
57071 // we entered the draw mode.
57072 nextMode = modeSelect(context, [wayID]);
57074 // The `undo` only removed the temporary edit, so here we have to
57075 // manually undo to actually remove the last node we added. We can't
57076 // use the `undo` function since the initial "add" graph doesn't have
57077 // an annotation and so cannot be undone to.
57078 context.pop(1); // continue drawing
57081 } // clear the redo stack by adding and removing a blank edit
57084 context.perform(actionNoop());
57086 context.resumeChangeDispatch();
57087 context.enter(nextMode);
57090 function setActiveElements() {
57091 if (!_drawNode) return;
57092 context.surface().selectAll('.' + _drawNode.id).classed('active', true);
57095 function resetToStartGraph() {
57096 while (context.graph() !== startGraph) {
57101 var drawWay = function drawWay(surface) {
57102 _drawNode = undefined;
57103 _didResolveTempEdit = false;
57104 _origWay = context.entity(wayID);
57106 if (typeof _nodeIndex === 'number') {
57107 _headNodeID = _origWay.nodes[_nodeIndex];
57108 } else if (_origWay.isClosed()) {
57109 _headNodeID = _origWay.nodes[_origWay.nodes.length - 2];
57111 _headNodeID = _origWay.nodes[_origWay.nodes.length - 1];
57114 _wayGeometry = _origWay.geometry(context.graph());
57115 _annotation = _t((_origWay.nodes.length === (_origWay.isClosed() ? 2 : 1) ? 'operations.start.annotation.' : 'operations.continue.annotation.') + _wayGeometry);
57116 _pointerHasMoved = false; // Push an annotated state for undo to return back to.
57117 // We must make sure to replace or remove it later.
57119 context.pauseChangeDispatch();
57120 context.perform(actionNoop(), _annotation);
57121 context.resumeChangeDispatch();
57122 behavior.hover().initialNodeID(_headNodeID);
57123 behavior.on('move', function () {
57124 _pointerHasMoved = true;
57125 move.apply(this, arguments);
57126 }).on('down', function () {
57127 move.apply(this, arguments);
57128 }).on('downcancel', function () {
57129 if (_drawNode) removeDrawNode();
57130 }).on('click', drawWay.add).on('clickWay', drawWay.addWay).on('clickNode', drawWay.addNode).on('undo', context.undo).on('cancel', drawWay.cancel).on('finish', drawWay.finish);
57131 select(window).on('keydown.drawWay', keydown).on('keyup.drawWay', keyup);
57132 context.map().dblclickZoomEnable(false).on('drawn.draw', setActiveElements);
57133 setActiveElements();
57134 surface.call(behavior);
57135 context.history().on('undone.draw', undone);
57138 drawWay.off = function (surface) {
57139 if (!_didResolveTempEdit) {
57140 // Drawing was interrupted unexpectedly.
57141 // This can happen if the user changes modes,
57142 // clicks geolocate button, a hashchange event occurs, etc.
57143 context.pauseChangeDispatch();
57144 resetToStartGraph();
57145 context.resumeChangeDispatch();
57148 _drawNode = undefined;
57149 _nodeIndex = undefined;
57150 context.map().on('drawn.draw', null);
57151 surface.call(behavior.off).selectAll('.active').classed('active', false);
57152 surface.classed('nope', false).classed('nope-suppressed', false).classed('nope-disabled', false);
57153 select(window).on('keydown.drawWay', null).on('keyup.drawWay', null);
57154 context.history().on('undone.draw', null);
57157 function attemptAdd(d, loc, doAdd) {
57159 // move the node to the final loc in case move wasn't called
57160 // consistently (e.g. on touch devices)
57161 context.replace(actionMoveNode(_drawNode.id, loc), _annotation);
57162 _drawNode = context.entity(_drawNode.id);
57164 createDrawNode(loc);
57168 /* includeDrawNode */
57171 if (d && d.properties && d.properties.nope || context.surface().classed('nope')) {
57172 if (!_pointerHasMoved) {
57173 // prevent the temporary draw node from appearing on touch devices
57177 dispatch.call('rejectedSelfIntersection', this);
57178 return; // can't click here
57181 context.pauseChangeDispatch();
57182 doAdd(); // we just replaced the temporary edit with the real one
57184 _didResolveTempEdit = true;
57185 context.resumeChangeDispatch();
57186 context.enter(mode);
57187 } // Accept the current position of the drawing node
57190 drawWay.add = function (loc, d) {
57191 attemptAdd(d, loc, function () {// don't need to do anything extra
57193 }; // Connect the way to an existing way
57196 drawWay.addWay = function (loc, edge, d) {
57197 attemptAdd(d, loc, function () {
57198 context.replace(actionAddMidpoint({
57201 }, _drawNode), _annotation);
57203 }; // Connect the way to an existing node
57206 drawWay.addNode = function (node, d) {
57207 // finish drawing if the mapper targets the prior node
57208 if (node.id === _headNodeID || // or the first node when drawing an area
57209 _origWay.isClosed() && node.id === _origWay.first()) {
57214 attemptAdd(d, node.loc, function () {
57215 context.replace(function actionReplaceDrawNode(graph) {
57216 // remove the temporary draw node and insert the existing node
57217 // at the same index
57218 graph = graph.replace(graph.entity(wayID).removeNode(_drawNode.id)).remove(_drawNode);
57219 return graph.replace(graph.entity(wayID).addNode(node.id, _nodeIndex));
57224 * @param {(typeof osmWay)[]} ways
57225 * @returns {"line" | "area" | "generic"}
57229 function getFeatureType(ways) {
57230 if (ways.every(function (way) {
57231 return way.isClosed();
57233 if (ways.every(function (way) {
57234 return !way.isClosed();
57238 /** see PR #8671 */
57241 function followMode() {
57242 if (_didResolveTempEdit) return;
57245 // get the last 2 added nodes.
57246 // check if they are both part of only oneway (the same one)
57247 // check if the ways that they're part of are the same way
57248 // find index of the last two nodes, to determine the direction to travel around the existing way
57249 // add the next node to the way we are drawing
57250 // if we're drawing an area, the first node = last node.
57251 var isDrawingArea = _origWay.nodes[0] === _origWay.nodes.slice(-1)[0];
57253 var _origWay$nodes$slice = _origWay.nodes.slice(isDrawingArea ? -3 : -2),
57254 _origWay$nodes$slice2 = _slicedToArray(_origWay$nodes$slice, 2),
57255 secondLastNodeId = _origWay$nodes$slice2[0],
57256 lastNodeId = _origWay$nodes$slice2[1]; // Unlike startGraph, the full history graph may contain unsaved vertices to follow.
57257 // https://github.com/openstreetmap/iD/issues/8749
57260 var historyGraph = context.history().graph();
57262 if (!lastNodeId || !secondLastNodeId || !historyGraph.hasEntity(lastNodeId) || !historyGraph.hasEntity(secondLastNodeId)) {
57263 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.follow.error.needs_more_initial_nodes'))();
57265 } // If the way has looped over itself, follow some other way.
57268 var lastNodesParents = historyGraph.parentWays(historyGraph.entity(lastNodeId)).filter(function (w) {
57269 return w.id !== wayID;
57271 var secondLastNodesParents = historyGraph.parentWays(historyGraph.entity(secondLastNodeId)).filter(function (w) {
57272 return w.id !== wayID;
57274 var featureType = getFeatureType(lastNodesParents);
57276 if (lastNodesParents.length !== 1 || secondLastNodesParents.length === 0) {
57277 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t("operations.follow.error.intersection_of_multiple_ways.".concat(featureType)))();
57279 } // Check if the last node's parent is also the parent of the second last node.
57280 // The last node must only have one parent, but the second last node can have
57281 // multiple parents.
57284 if (!secondLastNodesParents.some(function (n) {
57285 return n.id === lastNodesParents[0].id;
57287 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t("operations.follow.error.intersection_of_different_ways.".concat(featureType)))();
57291 var way = lastNodesParents[0];
57292 var indexOfLast = way.nodes.indexOf(lastNodeId);
57293 var indexOfSecondLast = way.nodes.indexOf(secondLastNodeId); // for a closed way, the first/last node is the same so it appears twice in the array,
57294 // but indexOf always finds the first occurrence. This is only an issue when following a way
57295 // in descending order
57297 var isDescendingPastZero = indexOfLast === way.nodes.length - 2 && indexOfSecondLast === 0;
57298 var nextNodeIndex = indexOfLast + (indexOfLast > indexOfSecondLast && !isDescendingPastZero ? 1 : -1); // if we're following a closed way and we pass the first/last node, the next index will be -1
57300 if (nextNodeIndex === -1) nextNodeIndex = indexOfSecondLast === 1 ? way.nodes.length - 2 : 1;
57301 var nextNode = historyGraph.entity(way.nodes[nextNodeIndex]);
57302 drawWay.addNode(nextNode, {
57305 coordinates: nextNode.loc
57314 context.ui().flash.duration(4000).iconName('#iD-icon-no').label(_t('operations.follow.error.unknown'))();
57318 keybinding.on(_t('operations.follow.key'), followMode);
57319 select(document).call(keybinding); // Finish the draw operation, removing the temporary edit.
57320 // If the way has enough nodes to be valid, it's selected.
57321 // Otherwise, delete everything and return to browse mode.
57323 drawWay.finish = function () {
57324 checkGeometry(false
57325 /* includeDrawNode */
57328 if (context.surface().classed('nope')) {
57329 dispatch.call('rejectedSelfIntersection', this);
57330 return; // can't click here
57333 context.pauseChangeDispatch(); // remove the temporary edit
57336 _didResolveTempEdit = true;
57337 context.resumeChangeDispatch();
57338 var way = context.hasEntity(wayID);
57340 if (!way || way.isDegenerate()) {
57345 window.setTimeout(function () {
57346 context.map().dblclickZoomEnable(true);
57348 var isNewFeature = !mode.isContinuing;
57349 context.enter(modeSelect(context, [wayID]).newFeature(isNewFeature));
57350 }; // Cancel the draw operation, delete everything, and return to browse mode.
57353 drawWay.cancel = function () {
57354 context.pauseChangeDispatch();
57355 resetToStartGraph();
57356 context.resumeChangeDispatch();
57357 window.setTimeout(function () {
57358 context.map().dblclickZoomEnable(true);
57360 context.surface().classed('nope', false).classed('nope-disabled', false).classed('nope-suppressed', false);
57361 context.enter(modeBrowse(context));
57364 drawWay.nodeIndex = function (val) {
57365 if (!arguments.length) return _nodeIndex;
57370 drawWay.activeID = function () {
57371 if (!arguments.length) return _drawNode && _drawNode.id; // no assign
57376 return utilRebind(drawWay, dispatch, 'on');
57379 function modeDrawLine(context, wayID, startGraph, button, affix, continuing) {
57384 var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawLine', function () {
57385 context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.lines'))();
57387 mode.wayID = wayID;
57388 mode.isContinuing = continuing;
57390 mode.enter = function () {
57391 behavior.nodeIndex(affix === 'prefix' ? 0 : undefined);
57392 context.install(behavior);
57395 mode.exit = function () {
57396 context.uninstall(behavior);
57399 mode.selectedIDs = function () {
57403 mode.activeID = function () {
57404 return behavior && behavior.activeID() || [];
57410 function validationDisconnectedWay() {
57411 var type = 'disconnected_way';
57413 function isTaggedAsHighway(entity) {
57414 return osmRoutableHighwayTagValues[entity.tags.highway];
57417 var validation = function checkDisconnectedWay(entity, graph) {
57418 var routingIslandWays = routingIslandForEntity(entity);
57419 if (!routingIslandWays) return [];
57420 return [new validationIssue({
57422 subtype: 'highway',
57423 severity: 'warning',
57424 message: function message(context) {
57425 var entity = this.entityIds.length && context.hasEntity(this.entityIds[0]);
57426 var label = entity && utilDisplayLabel(entity, context.graph());
57427 return _t.html('issues.disconnected_way.routable.message', {
57428 count: this.entityIds.length,
57432 reference: showReference,
57433 entityIds: Array.from(routingIslandWays).map(function (way) {
57436 dynamicFixes: makeFixes
57439 function makeFixes(context) {
57441 var singleEntity = this.entityIds.length === 1 && context.hasEntity(this.entityIds[0]);
57443 if (singleEntity) {
57444 if (singleEntity.type === 'way' && !singleEntity.isClosed()) {
57445 var textDirection = _mainLocalizer.textDirection();
57446 var startFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.first(), 'start');
57447 if (startFix) fixes.push(startFix);
57448 var endFix = makeContinueDrawingFixIfAllowed(textDirection, singleEntity.last(), 'end');
57449 if (endFix) fixes.push(endFix);
57452 if (!fixes.length) {
57453 fixes.push(new validationIssueFix({
57454 title: _t.html('issues.fix.connect_feature.title')
57458 fixes.push(new validationIssueFix({
57459 icon: 'iD-operation-delete',
57460 title: _t.html('issues.fix.delete_feature.title'),
57461 entityIds: [singleEntity.id],
57462 onClick: function onClick(context) {
57463 var id = this.issue.entityIds[0];
57464 var operation = operationDelete(context, [id]);
57466 if (!operation.disabled()) {
57472 fixes.push(new validationIssueFix({
57473 title: _t.html('issues.fix.connect_features.title')
57480 function showReference(selection) {
57481 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.disconnected_way.routable.reference'));
57484 function routingIslandForEntity(entity) {
57485 var routingIsland = new Set(); // the interconnected routable features
57487 var waysToCheck = []; // the queue of remaining routable ways to traverse
57489 function queueParentWays(node) {
57490 graph.parentWays(node).forEach(function (parentWay) {
57491 if (!routingIsland.has(parentWay) && // only check each feature once
57492 isRoutableWay(parentWay, false)) {
57493 // only check routable features
57494 routingIsland.add(parentWay);
57495 waysToCheck.push(parentWay);
57500 if (entity.type === 'way' && isRoutableWay(entity, true)) {
57501 routingIsland.add(entity);
57502 waysToCheck.push(entity);
57503 } else if (entity.type === 'node' && isRoutableNode(entity)) {
57504 routingIsland.add(entity);
57505 queueParentWays(entity);
57507 // this feature isn't routable, cannot be a routing island
57511 while (waysToCheck.length) {
57512 var wayToCheck = waysToCheck.pop();
57513 var childNodes = graph.childNodes(wayToCheck);
57515 for (var i in childNodes) {
57516 var vertex = childNodes[i];
57518 if (isConnectedVertex(vertex)) {
57519 // found a link to the wider network, not a routing island
57523 if (isRoutableNode(vertex)) {
57524 routingIsland.add(vertex);
57527 queueParentWays(vertex);
57529 } // no network link found, this is a routing island, return its members
57532 return routingIsland;
57535 function isConnectedVertex(vertex) {
57536 // assume ways overlapping unloaded tiles are connected to the wider road network - #5938
57537 var osm = services.osm;
57538 if (osm && !osm.isDataLoaded(vertex.loc)) return true; // entrances are considered connected
57540 if (vertex.tags.entrance && vertex.tags.entrance !== 'no') return true;
57541 if (vertex.tags.amenity === 'parking_entrance') return true;
57545 function isRoutableNode(node) {
57546 // treat elevators as distinct features in the highway network
57547 if (node.tags.highway === 'elevator') return true;
57551 function isRoutableWay(way, ignoreInnerWays) {
57552 if (isTaggedAsHighway(way) || way.tags.route === 'ferry') return true;
57553 return graph.parentRelations(way).some(function (parentRelation) {
57554 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true;
57555 if (parentRelation.isMultipolygon() && isTaggedAsHighway(parentRelation) && (!ignoreInnerWays || parentRelation.memberById(way.id).role !== 'inner')) return true;
57560 function makeContinueDrawingFixIfAllowed(textDirection, vertexID, whichEnd) {
57561 var vertex = graph.hasEntity(vertexID);
57562 if (!vertex || vertex.tags.noexit === 'yes') return null;
57563 var useLeftContinue = whichEnd === 'start' && textDirection === 'ltr' || whichEnd === 'end' && textDirection === 'rtl';
57564 return new validationIssueFix({
57565 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
57566 title: _t.html('issues.fix.continue_from_' + whichEnd + '.title'),
57567 entityIds: [vertexID],
57568 onClick: function onClick(context) {
57569 var wayId = this.issue.entityIds[0];
57570 var way = context.hasEntity(wayId);
57571 var vertexId = this.entityIds[0];
57572 var vertex = context.hasEntity(vertexId);
57573 if (!way || !vertex) return; // make sure the vertex is actually visible and editable
57575 var map = context.map();
57577 if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
57578 map.zoomToEase(vertex);
57581 context.enter(modeDrawLine(context, wayId, context.graph(), 'line', way.affix(vertexId), true));
57587 validation.type = type;
57591 function validationFormatting() {
57592 var type = 'invalid_format';
57594 var validation = function validation(entity) {
57597 function isValidEmail(email) {
57598 // Emails in OSM are going to be official so they should be pretty simple
57599 // Using negated lists to better support all possible unicode characters (#6494)
57600 var valid_email = /^[^\(\)\\,":;<>@\[\]]+@[^\(\)\\,":;<>@\[\]\.]+(?:\.[a-z0-9-]+)*$/i; // An empty value is also acceptable
57602 return !email || valid_email.test(email);
57605 function isSchemePresent(url) {
57606 var valid_scheme = /^https?:\/\//i;
57607 return (!url || valid_scheme.test(url));
57612 function showReferenceEmail(selection) {
57613 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.invalid_format.email.reference'));
57616 function showReferenceWebsite(selection) {
57617 selection.selectAll('.issue-reference')
57621 .attr('class', 'issue-reference')
57622 .html(t.html('issues.invalid_format.website.reference'));
57624 if (entity.tags.website) {
57625 // Multiple websites are possible
57626 // If ever we support ES6, arrow functions make this nicer
57627 var websites = entity.tags.website
57629 .map(function(s) { return s.trim(); })
57630 .filter(function(x) { return !isSchemePresent(x); });
57631 if (websites.length) {
57632 issues.push(new validationIssue({
57634 subtype: 'website',
57635 severity: 'warning',
57636 message: function(context) {
57637 var entity = context.hasEntity(this.entityIds[0]);
57638 return entity ? t.html('issues.invalid_format.website.message' + this.data,
57639 { feature: utilDisplayLabel(entity, context.graph()), site: websites.join(', ') }) : '';
57641 reference: showReferenceWebsite,
57642 entityIds: [entity.id],
57643 hash: websites.join(),
57644 data: (websites.length > 1) ? '_multi' : ''
57651 if (entity.tags.email) {
57652 // Multiple emails are possible
57653 var emails = entity.tags.email.split(';').map(function (s) {
57655 }).filter(function (x) {
57656 return !isValidEmail(x);
57659 if (emails.length) {
57660 issues.push(new validationIssue({
57663 severity: 'warning',
57664 message: function message(context) {
57665 var entity = context.hasEntity(this.entityIds[0]);
57666 return entity ? _t.html('issues.invalid_format.email.message' + this.data, {
57667 feature: utilDisplayLabel(entity, context.graph()),
57668 email: emails.join(', ')
57671 reference: showReferenceEmail,
57672 entityIds: [entity.id],
57673 hash: emails.join(),
57674 data: emails.length > 1 ? '_multi' : ''
57682 validation.type = type;
57686 function validationHelpRequest(context) {
57687 var type = 'help_request';
57689 var validation = function checkFixmeTag(entity) {
57690 if (!entity.tags.fixme) return []; // don't flag fixmes on features added by the user
57692 if (entity.version === undefined) return [];
57694 if (entity.v !== undefined) {
57695 var baseEntity = context.history().base().hasEntity(entity.id); // don't flag fixmes added by the user on existing features
57697 if (!baseEntity || !baseEntity.tags.fixme) return [];
57700 return [new validationIssue({
57702 subtype: 'fixme_tag',
57703 severity: 'warning',
57704 message: function message(context) {
57705 var entity = context.hasEntity(this.entityIds[0]);
57706 return entity ? _t.html('issues.fixme_tag.message', {
57707 feature: utilDisplayLabel(entity, context.graph(), true
57712 dynamicFixes: function dynamicFixes() {
57713 return [new validationIssueFix({
57714 title: _t.html('issues.fix.address_the_concern.title')
57717 reference: showReference,
57718 entityIds: [entity.id]
57721 function showReference(selection) {
57722 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.fixme_tag.reference'));
57726 validation.type = type;
57730 function validationImpossibleOneway() {
57731 var type = 'impossible_oneway';
57733 var validation = function checkImpossibleOneway(entity, graph) {
57734 if (entity.type !== 'way' || entity.geometry(graph) !== 'line') return [];
57735 if (entity.isClosed()) return [];
57736 if (!typeForWay(entity)) return [];
57737 if (!isOneway(entity)) return [];
57738 var firstIssues = issuesForNode(entity, entity.first());
57739 var lastIssues = issuesForNode(entity, entity.last());
57740 return firstIssues.concat(lastIssues);
57742 function typeForWay(way) {
57743 if (way.geometry(graph) !== 'line') return null;
57744 if (osmRoutableHighwayTagValues[way.tags.highway]) return 'highway';
57745 if (osmFlowingWaterwayTagValues[way.tags.waterway]) return 'waterway';
57749 function isOneway(way) {
57750 if (way.tags.oneway === 'yes') return true;
57751 if (way.tags.oneway) return false;
57753 for (var key in way.tags) {
57754 if (osmOneWayTags[key] && osmOneWayTags[key][way.tags[key]]) {
57762 function nodeOccursMoreThanOnce(way, nodeID) {
57763 var occurrences = 0;
57765 for (var index in way.nodes) {
57766 if (way.nodes[index] === nodeID) {
57768 if (occurrences > 1) return true;
57775 function isConnectedViaOtherTypes(way, node) {
57776 var wayType = typeForWay(way);
57778 if (wayType === 'highway') {
57779 // entrances are considered connected
57780 if (node.tags.entrance && node.tags.entrance !== 'no') return true;
57781 if (node.tags.amenity === 'parking_entrance') return true;
57782 } else if (wayType === 'waterway') {
57783 if (node.id === way.first()) {
57784 // multiple waterways may start at the same spring
57785 if (node.tags.natural === 'spring') return true;
57787 // multiple waterways may end at the same drain
57788 if (node.tags.manhole === 'drain') return true;
57792 return graph.parentWays(node).some(function (parentWay) {
57793 if (parentWay.id === way.id) return false;
57795 if (wayType === 'highway') {
57796 // allow connections to highway areas
57797 if (parentWay.geometry(graph) === 'area' && osmRoutableHighwayTagValues[parentWay.tags.highway]) return true; // count connections to ferry routes as connected
57799 if (parentWay.tags.route === 'ferry') return true;
57800 return graph.parentRelations(parentWay).some(function (parentRelation) {
57801 if (parentRelation.tags.type === 'route' && parentRelation.tags.route === 'ferry') return true; // allow connections to highway multipolygons
57803 return parentRelation.isMultipolygon() && osmRoutableHighwayTagValues[parentRelation.tags.highway];
57805 } else if (wayType === 'waterway') {
57806 // multiple waterways may start or end at a water body at the same node
57807 if (parentWay.tags.natural === 'water' || parentWay.tags.natural === 'coastline') return true;
57814 function issuesForNode(way, nodeID) {
57815 var isFirst = nodeID === way.first();
57816 var wayType = typeForWay(way); // ignore if this way is self-connected at this node
57818 if (nodeOccursMoreThanOnce(way, nodeID)) return [];
57819 var osm = services.osm;
57820 if (!osm) return [];
57821 var node = graph.hasEntity(nodeID); // ignore if this node or its tile are unloaded
57823 if (!node || !osm.isDataLoaded(node.loc)) return [];
57824 if (isConnectedViaOtherTypes(way, node)) return [];
57825 var attachedWaysOfSameType = graph.parentWays(node).filter(function (parentWay) {
57826 if (parentWay.id === way.id) return false;
57827 return typeForWay(parentWay) === wayType;
57828 }); // assume it's okay for waterways to start or end disconnected for now
57830 if (wayType === 'waterway' && attachedWaysOfSameType.length === 0) return [];
57831 var attachedOneways = attachedWaysOfSameType.filter(function (attachedWay) {
57832 return isOneway(attachedWay);
57833 }); // ignore if the way is connected to some non-oneway features
57835 if (attachedOneways.length < attachedWaysOfSameType.length) return [];
57837 if (attachedOneways.length) {
57838 var connectedEndpointsOkay = attachedOneways.some(function (attachedOneway) {
57839 if ((isFirst ? attachedOneway.first() : attachedOneway.last()) !== nodeID) return true;
57840 if (nodeOccursMoreThanOnce(attachedOneway, nodeID)) return true;
57843 if (connectedEndpointsOkay) return [];
57846 var placement = isFirst ? 'start' : 'end',
57847 messageID = wayType + '.',
57848 referenceID = wayType + '.';
57850 if (wayType === 'waterway') {
57851 messageID += 'connected.' + placement;
57852 referenceID += 'connected';
57854 messageID += placement;
57855 referenceID += placement;
57858 return [new validationIssue({
57861 severity: 'warning',
57862 message: function message(context) {
57863 var entity = context.hasEntity(this.entityIds[0]);
57864 return entity ? _t.html('issues.impossible_oneway.' + messageID + '.message', {
57865 feature: utilDisplayLabel(entity, context.graph())
57868 reference: getReference(referenceID),
57869 entityIds: [way.id, node.id],
57870 dynamicFixes: function dynamicFixes() {
57873 if (attachedOneways.length) {
57874 fixes.push(new validationIssueFix({
57875 icon: 'iD-operation-reverse',
57876 title: _t.html('issues.fix.reverse_feature.title'),
57877 entityIds: [way.id],
57878 onClick: function onClick(context) {
57879 var id = this.issue.entityIds[0];
57880 context.perform(actionReverse(id), _t('operations.reverse.annotation.line', {
57887 if (node.tags.noexit !== 'yes') {
57888 var textDirection = _mainLocalizer.textDirection();
57889 var useLeftContinue = isFirst && textDirection === 'ltr' || !isFirst && textDirection === 'rtl';
57890 fixes.push(new validationIssueFix({
57891 icon: 'iD-operation-continue' + (useLeftContinue ? '-left' : ''),
57892 title: _t.html('issues.fix.continue_from_' + (isFirst ? 'start' : 'end') + '.title'),
57893 onClick: function onClick(context) {
57894 var entityID = this.issue.entityIds[0];
57895 var vertexID = this.issue.entityIds[1];
57896 var way = context.entity(entityID);
57897 var vertex = context.entity(vertexID);
57898 continueDrawing(way, vertex, context);
57908 function getReference(referenceID) {
57909 return function showReference(selection) {
57910 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.impossible_oneway.' + referenceID + '.reference'));
57916 function continueDrawing(way, vertex, context) {
57917 // make sure the vertex is actually visible and editable
57918 var map = context.map();
57920 if (!context.editable() || !map.trimmedExtent().contains(vertex.loc)) {
57921 map.zoomToEase(vertex);
57924 context.enter(modeDrawLine(context, way.id, context.graph(), 'line', way.affix(vertex.id), true));
57927 validation.type = type;
57931 function validationIncompatibleSource() {
57932 var type = 'incompatible_source';
57933 var incompatibleRules = [{
57935 regex: /(amap|autonavi|mapabc|高德)/i
57938 regex: /(baidu|mapbar|百度)/i
57942 exceptRegex: /((books|drive)\.google|google\s?(books|drive|plus))/i
57945 var validation = function checkIncompatibleSource(entity) {
57946 var entitySources = entity.tags && entity.tags.source && entity.tags.source.split(';');
57947 if (!entitySources) return [];
57948 var entityID = entity.id;
57949 return entitySources.map(function (source) {
57950 var matchRule = incompatibleRules.find(function (rule) {
57951 if (!rule.regex.test(source)) return false;
57952 if (rule.exceptRegex && rule.exceptRegex.test(source)) return false;
57955 if (!matchRule) return null;
57956 return new validationIssue({
57958 severity: 'warning',
57959 message: function message(context) {
57960 var entity = context.hasEntity(entityID);
57961 return entity ? _t.html('issues.incompatible_source.feature.message', {
57962 feature: utilDisplayLabel(entity, context.graph(), true
57968 reference: getReference(matchRule.id),
57969 entityIds: [entityID],
57971 dynamicFixes: function dynamicFixes() {
57972 return [new validationIssueFix({
57973 title: _t.html('issues.fix.remove_proprietary_data.title')
57977 }).filter(Boolean);
57979 function getReference(id) {
57980 return function showReference(selection) {
57981 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html("issues.incompatible_source.reference.".concat(id)));
57986 validation.type = type;
57990 function validationMaprules() {
57991 var type = 'maprules';
57993 var validation = function checkMaprules(entity, graph) {
57994 if (!services.maprules) return [];
57995 var rules = services.maprules.validationRules();
57998 for (var i = 0; i < rules.length; i++) {
57999 var rule = rules[i];
58000 rule.findIssues(entity, graph, issues);
58006 validation.type = type;
58010 function validationMismatchedGeometry() {
58011 var type = 'mismatched_geometry';
58013 function tagSuggestingLineIsArea(entity) {
58014 if (entity.type !== 'way' || entity.isClosed()) return null;
58015 var tagSuggestingArea = entity.tagSuggestingArea();
58017 if (!tagSuggestingArea) {
58021 var asLine = _mainPresetIndex.matchTags(tagSuggestingArea, 'line');
58022 var asArea = _mainPresetIndex.matchTags(tagSuggestingArea, 'area');
58024 if (asLine && asArea && asLine === asArea) {
58025 // these tags also allow lines and making this an area wouldn't matter
58029 return tagSuggestingArea;
58032 function makeConnectEndpointsFixOnClick(way, graph) {
58033 // must have at least three nodes to close this automatically
58034 if (way.nodes.length < 3) return null;
58035 var nodes = graph.childNodes(way),
58037 var firstToLastDistanceMeters = geoSphericalDistance(nodes[0].loc, nodes[nodes.length - 1].loc); // if the distance is very small, attempt to merge the endpoints
58039 if (firstToLastDistanceMeters < 0.75) {
58040 testNodes = nodes.slice(); // shallow copy
58043 testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
58045 if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
58046 return function (context) {
58047 var way = context.entity(this.issue.entityIds[0]);
58048 context.perform(actionMergeNodes([way.nodes[0], way.nodes[way.nodes.length - 1]], nodes[0].loc), _t('issues.fix.connect_endpoints.annotation'));
58051 } // if the points were not merged, attempt to close the way
58054 testNodes = nodes.slice(); // shallow copy
58056 testNodes.push(testNodes[0]); // make sure this will not create a self-intersection
58058 if (!geoHasSelfIntersections(testNodes, testNodes[0].id)) {
58059 return function (context) {
58060 var wayId = this.issue.entityIds[0];
58061 var way = context.entity(wayId);
58062 var nodeId = way.nodes[0];
58063 var index = way.nodes.length;
58064 context.perform(actionAddVertex(wayId, nodeId, index), _t('issues.fix.connect_endpoints.annotation'));
58069 function lineTaggedAsAreaIssue(entity) {
58070 var tagSuggestingArea = tagSuggestingLineIsArea(entity);
58071 if (!tagSuggestingArea) return null;
58072 return new validationIssue({
58074 subtype: 'area_as_line',
58075 severity: 'warning',
58076 message: function message(context) {
58077 var entity = context.hasEntity(this.entityIds[0]);
58078 return entity ? _t.html('issues.tag_suggests_area.message', {
58079 feature: utilDisplayLabel(entity, 'area', true
58083 tags: tagSuggestingArea
58087 reference: showReference,
58088 entityIds: [entity.id],
58089 hash: JSON.stringify(tagSuggestingArea),
58090 dynamicFixes: function dynamicFixes(context) {
58092 var entity = context.entity(this.entityIds[0]);
58093 var connectEndsOnClick = makeConnectEndpointsFixOnClick(entity, context.graph());
58094 fixes.push(new validationIssueFix({
58095 title: _t.html('issues.fix.connect_endpoints.title'),
58096 onClick: connectEndsOnClick
58098 fixes.push(new validationIssueFix({
58099 icon: 'iD-operation-delete',
58100 title: _t.html('issues.fix.remove_tag.title'),
58101 onClick: function onClick(context) {
58102 var entityId = this.issue.entityIds[0];
58103 var entity = context.entity(entityId);
58104 var tags = Object.assign({}, entity.tags); // shallow copy
58106 for (var key in tagSuggestingArea) {
58110 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_tag.annotation'));
58117 function showReference(selection) {
58118 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.tag_suggests_area.reference'));
58122 function vertexPointIssue(entity, graph) {
58123 // we only care about nodes
58124 if (entity.type !== 'node') return null; // ignore tagless points
58126 if (Object.keys(entity.tags).length === 0) return null; // address lines are special so just ignore them
58128 if (entity.isOnAddressLine(graph)) return null;
58129 var geometry = entity.geometry(graph);
58130 var allowedGeometries = osmNodeGeometriesForTags(entity.tags);
58132 if (geometry === 'point' && !allowedGeometries.point && allowedGeometries.vertex) {
58133 return new validationIssue({
58135 subtype: 'vertex_as_point',
58136 severity: 'warning',
58137 message: function message(context) {
58138 var entity = context.hasEntity(this.entityIds[0]);
58139 return entity ? _t.html('issues.vertex_as_point.message', {
58140 feature: utilDisplayLabel(entity, 'vertex', true
58145 reference: function showReference(selection) {
58146 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.vertex_as_point.reference'));
58148 entityIds: [entity.id]
58150 } else if (geometry === 'vertex' && !allowedGeometries.vertex && allowedGeometries.point) {
58151 return new validationIssue({
58153 subtype: 'point_as_vertex',
58154 severity: 'warning',
58155 message: function message(context) {
58156 var entity = context.hasEntity(this.entityIds[0]);
58157 return entity ? _t.html('issues.point_as_vertex.message', {
58158 feature: utilDisplayLabel(entity, 'point', true
58163 reference: function showReference(selection) {
58164 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.point_as_vertex.reference'));
58166 entityIds: [entity.id],
58167 dynamicFixes: extractPointDynamicFixes
58174 function otherMismatchIssue(entity, graph) {
58175 // ignore boring features
58176 if (!entity.hasInterestingTags()) return null;
58177 if (entity.type !== 'node' && entity.type !== 'way') return null; // address lines are special so just ignore them
58179 if (entity.type === 'node' && entity.isOnAddressLine(graph)) return null;
58180 var sourceGeom = entity.geometry(graph);
58181 var targetGeoms = entity.type === 'way' ? ['point', 'vertex'] : ['line', 'area'];
58182 if (sourceGeom === 'area') targetGeoms.unshift('line');
58183 var asSource = _mainPresetIndex.match(entity, graph);
58184 var targetGeom = targetGeoms.find(function (nodeGeom) {
58185 var asTarget = _mainPresetIndex.matchTags(entity.tags, nodeGeom);
58186 if (!asSource || !asTarget || asSource === asTarget || // sometimes there are two presets with the same tags for different geometries
58187 fastDeepEqual(asSource.tags, asTarget.tags)) return false;
58188 if (asTarget.isFallback()) return false;
58189 var primaryKey = Object.keys(asTarget.tags)[0]; // special case: buildings-as-points are discouraged by iD, but common in OSM, so ignore them
58191 if (primaryKey === 'building') return false;
58192 if (asTarget.tags[primaryKey] === '*') return false;
58193 return asSource.isFallback() || asSource.tags[primaryKey] === '*';
58195 if (!targetGeom) return null;
58196 var subtype = targetGeom + '_as_' + sourceGeom;
58197 if (targetGeom === 'vertex') targetGeom = 'point';
58198 if (sourceGeom === 'vertex') sourceGeom = 'point';
58199 var referenceId = targetGeom + '_as_' + sourceGeom;
58202 if (targetGeom === 'point') {
58203 dynamicFixes = extractPointDynamicFixes;
58204 } else if (sourceGeom === 'area' && targetGeom === 'line') {
58205 dynamicFixes = lineToAreaDynamicFixes;
58208 return new validationIssue({
58211 severity: 'warning',
58212 message: function message(context) {
58213 var entity = context.hasEntity(this.entityIds[0]);
58214 return entity ? _t.html('issues.' + referenceId + '.message', {
58215 feature: utilDisplayLabel(entity, targetGeom, true
58220 reference: function showReference(selection) {
58221 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.mismatched_geometry.reference'));
58223 entityIds: [entity.id],
58224 dynamicFixes: dynamicFixes
58228 function lineToAreaDynamicFixes(context) {
58229 var convertOnClick;
58230 var entityId = this.entityIds[0];
58231 var entity = context.entity(entityId);
58232 var tags = Object.assign({}, entity.tags); // shallow copy
58236 if (!osmTagSuggestingArea(tags)) {
58237 // if removing the area tag would make this a line, offer that as a quick fix
58238 convertOnClick = function convertOnClick(context) {
58239 var entityId = this.issue.entityIds[0];
58240 var entity = context.entity(entityId);
58241 var tags = Object.assign({}, entity.tags); // shallow copy
58247 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.convert_to_line.annotation'));
58251 return [new validationIssueFix({
58252 icon: 'iD-icon-line',
58253 title: _t.html('issues.fix.convert_to_line.title'),
58254 onClick: convertOnClick
58258 function extractPointDynamicFixes(context) {
58259 var entityId = this.entityIds[0];
58260 var extractOnClick = null;
58262 if (!context.hasHiddenConnections(entityId)) {
58263 extractOnClick = function extractOnClick(context) {
58264 var entityId = this.issue.entityIds[0];
58265 var action = actionExtract(entityId, context.projection);
58266 context.perform(action, _t('operations.extract.annotation', {
58268 })); // re-enter mode to trigger updates
58270 context.enter(modeSelect(context, [action.getExtractedNodeID()]));
58274 return [new validationIssueFix({
58275 icon: 'iD-operation-extract',
58276 title: _t.html('issues.fix.extract_point.title'),
58277 onClick: extractOnClick
58281 function unclosedMultipolygonPartIssues(entity, graph) {
58282 if (entity.type !== 'relation' || !entity.isMultipolygon() || entity.isDegenerate() || // cannot determine issues for incompletely-downloaded relations
58283 !entity.isComplete(graph)) return [];
58284 var sequences = osmJoinWays(entity.members, graph);
58287 for (var i in sequences) {
58288 var sequence = sequences[i];
58289 if (!sequence.nodes) continue;
58290 var firstNode = sequence.nodes[0];
58291 var lastNode = sequence.nodes[sequence.nodes.length - 1]; // part is closed if the first and last nodes are the same
58293 if (firstNode === lastNode) continue;
58294 var issue = new validationIssue({
58296 subtype: 'unclosed_multipolygon_part',
58297 severity: 'warning',
58298 message: function message(context) {
58299 var entity = context.hasEntity(this.entityIds[0]);
58300 return entity ? _t.html('issues.unclosed_multipolygon_part.message', {
58301 feature: utilDisplayLabel(entity, context.graph(), true
58306 reference: showReference,
58307 loc: sequence.nodes[0].loc,
58308 entityIds: [entity.id],
58309 hash: sequence.map(function (way) {
58313 issues.push(issue);
58318 function showReference(selection) {
58319 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unclosed_multipolygon_part.reference'));
58323 var validation = function checkMismatchedGeometry(entity, graph) {
58324 var vertexPoint = vertexPointIssue(entity, graph);
58325 if (vertexPoint) return [vertexPoint];
58326 var lineAsArea = lineTaggedAsAreaIssue(entity);
58327 if (lineAsArea) return [lineAsArea];
58328 var mismatch = otherMismatchIssue(entity, graph);
58329 if (mismatch) return [mismatch];
58330 return unclosedMultipolygonPartIssues(entity, graph);
58333 validation.type = type;
58337 function validationMissingRole() {
58338 var type = 'missing_role';
58340 var validation = function checkMissingRole(entity, graph) {
58343 if (entity.type === 'way') {
58344 graph.parentRelations(entity).forEach(function (relation) {
58345 if (!relation.isMultipolygon()) return;
58346 var member = relation.memberById(entity.id);
58348 if (member && isMissingRole(member)) {
58349 issues.push(makeIssue(entity, relation, member));
58352 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
58353 entity.indexedMembers().forEach(function (member) {
58354 var way = graph.hasEntity(member.id);
58356 if (way && isMissingRole(member)) {
58357 issues.push(makeIssue(way, entity, member));
58365 function isMissingRole(member) {
58366 return !member.role || !member.role.trim().length;
58369 function makeIssue(way, relation, member) {
58370 return new validationIssue({
58372 severity: 'warning',
58373 message: function message(context) {
58374 var member = context.hasEntity(this.entityIds[1]),
58375 relation = context.hasEntity(this.entityIds[0]);
58376 return member && relation ? _t.html('issues.missing_role.message', {
58377 member: utilDisplayLabel(member, context.graph()),
58378 relation: utilDisplayLabel(relation, context.graph())
58381 reference: showReference,
58382 entityIds: [relation.id, way.id],
58386 hash: member.index.toString(),
58387 dynamicFixes: function dynamicFixes() {
58388 return [makeAddRoleFix('inner'), makeAddRoleFix('outer'), new validationIssueFix({
58389 icon: 'iD-operation-delete',
58390 title: _t.html('issues.fix.remove_from_relation.title'),
58391 onClick: function onClick(context) {
58392 context.perform(actionDeleteMember(this.issue.entityIds[0], this.issue.data.member.index), _t('operations.delete_member.annotation', {
58400 function showReference(selection) {
58401 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.missing_role.multipolygon.reference'));
58405 function makeAddRoleFix(role) {
58406 return new validationIssueFix({
58407 title: _t.html('issues.fix.set_as_' + role + '.title'),
58408 onClick: function onClick(context) {
58409 var oldMember = this.issue.data.member;
58411 id: this.issue.entityIds[1],
58412 type: oldMember.type,
58415 context.perform(actionChangeMember(this.issue.entityIds[0], member, oldMember.index), _t('operations.change_role.annotation', {
58422 validation.type = type;
58426 function validationMissingTag(context) {
58427 var type = 'missing_tag';
58429 function hasDescriptiveTags(entity, graph) {
58430 var onlyAttributeKeys = ['description', 'name', 'note', 'start_date'];
58431 var entityDescriptiveKeys = Object.keys(entity.tags).filter(function (k) {
58432 if (k === 'area' || !osmIsInterestingTag(k)) return false;
58433 return !onlyAttributeKeys.some(function (attributeKey) {
58434 return k === attributeKey || k.indexOf(attributeKey + ':') === 0;
58438 if (entity.type === 'relation' && entityDescriptiveKeys.length === 1 && entity.tags.type === 'multipolygon') {
58439 // this relation's only interesting tag just says its a multipolygon,
58440 // which is not descriptive enough
58441 // It's okay for a simple multipolygon to have no descriptive tags
58442 // if its outer way has them (old model, see `outdated_tags.js`)
58443 return osmOldMultipolygonOuterMemberOfRelation(entity, graph);
58446 return entityDescriptiveKeys.length > 0;
58449 function isUnknownRoad(entity) {
58450 return entity.type === 'way' && entity.tags.highway === 'road';
58453 function isUntypedRelation(entity) {
58454 return entity.type === 'relation' && !entity.tags.type;
58457 var validation = function checkMissingTag(entity, graph) {
58459 var osm = context.connection();
58460 var isUnloadedNode = entity.type === 'node' && osm && !osm.isDataLoaded(entity.loc); // we can't know if the node is a vertex if the tile is undownloaded
58462 if (!isUnloadedNode && // allow untagged nodes that are part of ways
58463 entity.geometry(graph) !== 'vertex' && // allow untagged entities that are part of relations
58464 !entity.hasParentRelations(graph)) {
58465 if (Object.keys(entity.tags).length === 0) {
58467 } else if (!hasDescriptiveTags(entity, graph)) {
58468 subtype = 'descriptive';
58469 } else if (isUntypedRelation(entity)) {
58470 subtype = 'relation_type';
58472 } // flag an unknown road even if it's a member of a relation
58475 if (!subtype && isUnknownRoad(entity)) {
58476 subtype = 'highway_classification';
58479 if (!subtype) return [];
58480 var messageID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag.' + subtype;
58481 var referenceID = subtype === 'highway_classification' ? 'unknown_road' : 'missing_tag'; // can always delete if the user created it in the first place..
58483 var canDelete = entity.version === undefined || entity.v !== undefined;
58484 var severity = canDelete && subtype !== 'highway_classification' ? 'error' : 'warning';
58485 return [new validationIssue({
58488 severity: severity,
58489 message: function message(context) {
58490 var entity = context.hasEntity(this.entityIds[0]);
58491 return entity ? _t.html('issues.' + messageID + '.message', {
58492 feature: utilDisplayLabel(entity, context.graph())
58495 reference: showReference,
58496 entityIds: [entity.id],
58497 dynamicFixes: function dynamicFixes(context) {
58499 var selectFixType = subtype === 'highway_classification' ? 'select_road_type' : 'select_preset';
58500 fixes.push(new validationIssueFix({
58501 icon: 'iD-icon-search',
58502 title: _t.html('issues.fix.' + selectFixType + '.title'),
58503 onClick: function onClick(context) {
58504 context.ui().sidebar.showPresetList();
58508 var id = this.entityIds[0];
58509 var operation = operationDelete(context, [id]);
58510 var disabledReasonID = operation.disabled();
58512 if (!disabledReasonID) {
58513 deleteOnClick = function deleteOnClick(context) {
58514 var id = this.issue.entityIds[0];
58515 var operation = operationDelete(context, [id]);
58517 if (!operation.disabled()) {
58523 fixes.push(new validationIssueFix({
58524 icon: 'iD-operation-delete',
58525 title: _t.html('issues.fix.delete_feature.title'),
58526 disabledReason: disabledReasonID ? _t('operations.delete.' + disabledReasonID + '.single') : undefined,
58527 onClick: deleteOnClick
58533 function showReference(selection) {
58534 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.' + referenceID + '.reference'));
58538 validation.type = type;
58542 function validationOutdatedTags() {
58543 var type = 'outdated_tags';
58544 var _waitingForDeprecated = true;
58546 var _dataDeprecated; // fetch deprecated tags
58549 _mainFileFetcher.get('deprecated').then(function (d) {
58550 return _dataDeprecated = d;
58551 })["catch"](function () {
58553 })["finally"](function () {
58554 return _waitingForDeprecated = false;
58557 function oldTagIssues(entity, graph) {
58558 var oldTags = Object.assign({}, entity.tags); // shallow copy
58560 var preset = _mainPresetIndex.match(entity, graph);
58561 var subtype = 'deprecated_tags';
58562 if (!preset) return [];
58563 if (!entity.hasInterestingTags()) return []; // Upgrade preset, if a replacement is available..
58565 if (preset.replacement) {
58566 var newPreset = _mainPresetIndex.item(preset.replacement);
58567 graph = actionChangePreset(entity.id, preset, newPreset, true
58568 /* skip field defaults */
58570 entity = graph.entity(entity.id);
58571 preset = newPreset;
58572 } // Upgrade deprecated tags..
58575 if (_dataDeprecated) {
58576 var deprecatedTags = entity.deprecatedTags(_dataDeprecated);
58578 if (deprecatedTags.length) {
58579 deprecatedTags.forEach(function (tag) {
58580 graph = actionUpgradeTags(entity.id, tag.old, tag.replace)(graph);
58582 entity = graph.entity(entity.id);
58584 } // Add missing addTags from the detected preset
58587 var newTags = Object.assign({}, entity.tags); // shallow copy
58589 if (preset.tags !== preset.addTags) {
58590 Object.keys(preset.addTags).forEach(function (k) {
58592 if (preset.addTags[k] === '*') {
58593 newTags[k] = 'yes';
58595 newTags[k] = preset.addTags[k];
58599 } // Attempt to match a canonical record in the name-suggestion-index.
58602 var nsi = services.nsi;
58603 var waitingForNsi = false;
58607 waitingForNsi = nsi.status() === 'loading';
58609 if (!waitingForNsi) {
58610 var loc = entity.extent(graph).center();
58611 nsiResult = nsi.upgradeTags(newTags, loc);
58614 newTags = nsiResult.newTags;
58615 subtype = 'noncanonical_brand';
58621 issues.provisional = _waitingForDeprecated || waitingForNsi; // determine diff
58623 var tagDiff = utilTagDiff(oldTags, newTags);
58624 if (!tagDiff.length) return issues;
58625 var isOnlyAddingTags = tagDiff.every(function (d) {
58626 return d.type === '+';
58631 prefix = 'noncanonical_brand.';
58632 } else if (subtype === 'deprecated_tags' && isOnlyAddingTags) {
58633 subtype = 'incomplete_tags';
58634 prefix = 'incomplete.';
58635 } // don't allow autofixing brand tags
58638 var autoArgs = subtype !== 'noncanonical_brand' ? [doUpgrade, _t('issues.fix.upgrade_tags.annotation')] : null;
58639 issues.push(new validationIssue({
58642 severity: 'warning',
58643 message: showMessage,
58644 reference: showReference,
58645 entityIds: [entity.id],
58646 hash: utilHashcode(JSON.stringify(tagDiff)),
58647 dynamicFixes: function dynamicFixes() {
58648 var fixes = [new validationIssueFix({
58649 autoArgs: autoArgs,
58650 title: _t.html('issues.fix.upgrade_tags.title'),
58651 onClick: function onClick(context) {
58652 context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
58655 var item = nsiResult && nsiResult.matched;
58658 fixes.push(new validationIssueFix({
58659 title: _t.html('issues.fix.tag_as_not.title', {
58660 name: item.displayName
58662 onClick: function onClick(context) {
58663 context.perform(addNotTag, _t('issues.fix.tag_as_not.annotation'));
58673 function doUpgrade(graph) {
58674 var currEntity = graph.hasEntity(entity.id);
58675 if (!currEntity) return graph;
58676 var newTags = Object.assign({}, currEntity.tags); // shallow copy
58678 tagDiff.forEach(function (diff) {
58679 if (diff.type === '-') {
58680 delete newTags[diff.key];
58681 } else if (diff.type === '+') {
58682 newTags[diff.key] = diff.newVal;
58685 return actionChangeTags(currEntity.id, newTags)(graph);
58688 function addNotTag(graph) {
58689 var currEntity = graph.hasEntity(entity.id);
58690 if (!currEntity) return graph;
58691 var item = nsiResult && nsiResult.matched;
58692 if (!item) return graph;
58693 var newTags = Object.assign({}, currEntity.tags); // shallow copy
58695 var wd = item.mainTag; // e.g. `brand:wikidata`
58697 var notwd = "not:".concat(wd); // e.g. `not:brand:wikidata`
58699 var qid = item.tags[wd];
58700 newTags[notwd] = qid;
58702 if (newTags[wd] === qid) {
58703 // if `brand:wikidata` was set to that qid
58704 var wp = item.mainTag.replace('wikidata', 'wikipedia');
58705 delete newTags[wd]; // remove `brand:wikidata`
58707 delete newTags[wp]; // remove `brand:wikipedia`
58710 return actionChangeTags(currEntity.id, newTags)(graph);
58713 function showMessage(context) {
58714 var currEntity = context.hasEntity(entity.id);
58715 if (!currEntity) return '';
58716 var messageID = "issues.outdated_tags.".concat(prefix, "message");
58718 if (subtype === 'noncanonical_brand' && isOnlyAddingTags) {
58719 messageID += '_incomplete';
58722 return _t.html(messageID, {
58723 feature: utilDisplayLabel(currEntity, context.graph(), true
58729 function showReference(selection) {
58730 var enter = selection.selectAll('.issue-reference').data([0]).enter();
58731 enter.append('div').attr('class', 'issue-reference').html(_t.html("issues.outdated_tags.".concat(prefix, "reference")));
58732 enter.append('strong').html(_t.html('issues.suggested'));
58733 enter.append('table').attr('class', 'tagDiff-table').selectAll('.tagDiff-row').data(tagDiff).enter().append('tr').attr('class', 'tagDiff-row').append('td').attr('class', function (d) {
58734 var klass = d.type === '+' ? 'add' : 'remove';
58735 return "tagDiff-cell tagDiff-cell-".concat(klass);
58736 }).html(function (d) {
58742 function oldMultipolygonIssues(entity, graph) {
58743 var multipolygon, outerWay;
58745 if (entity.type === 'relation') {
58746 outerWay = osmOldMultipolygonOuterMemberOfRelation(entity, graph);
58747 multipolygon = entity;
58748 } else if (entity.type === 'way') {
58749 multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
58755 if (!multipolygon || !outerWay) return [];
58756 return [new validationIssue({
58758 subtype: 'old_multipolygon',
58759 severity: 'warning',
58760 message: showMessage,
58761 reference: showReference,
58762 entityIds: [outerWay.id, multipolygon.id],
58763 dynamicFixes: function dynamicFixes() {
58764 return [new validationIssueFix({
58765 autoArgs: [doUpgrade, _t('issues.fix.move_tags.annotation')],
58766 title: _t.html('issues.fix.move_tags.title'),
58767 onClick: function onClick(context) {
58768 context.perform(doUpgrade, _t('issues.fix.move_tags.annotation'));
58774 function doUpgrade(graph) {
58775 var currMultipolygon = graph.hasEntity(multipolygon.id);
58776 var currOuterWay = graph.hasEntity(outerWay.id);
58777 if (!currMultipolygon || !currOuterWay) return graph;
58778 currMultipolygon = currMultipolygon.mergeTags(currOuterWay.tags);
58779 graph = graph.replace(currMultipolygon);
58780 return actionChangeTags(currOuterWay.id, {})(graph);
58783 function showMessage(context) {
58784 var currMultipolygon = context.hasEntity(multipolygon.id);
58785 if (!currMultipolygon) return '';
58786 return _t.html('issues.old_multipolygon.message', {
58787 multipolygon: utilDisplayLabel(currMultipolygon, context.graph(), true
58793 function showReference(selection) {
58794 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.old_multipolygon.reference'));
58798 var validation = function checkOutdatedTags(entity, graph) {
58799 var issues = oldMultipolygonIssues(entity, graph);
58800 if (!issues.length) issues = oldTagIssues(entity, graph);
58804 validation.type = type;
58808 function validationPrivateData() {
58809 var type = 'private_data'; // assume that some buildings are private
58811 var privateBuildingValues = {
58817 semidetached_house: true,
58818 static_caravan: true
58819 }; // but they might be public if they have one of these other tags
58829 }; // these tags may contain personally identifying info
58831 var personalTags = {
58832 'contact:email': true,
58833 'contact:fax': true,
58834 'contact:phone': true,
58840 var validation = function checkPrivateData(entity) {
58841 var tags = entity.tags;
58842 if (!tags.building || !privateBuildingValues[tags.building]) return [];
58845 for (var k in tags) {
58846 if (publicKeys[k]) return []; // probably a public feature
58848 if (!personalTags[k]) {
58849 keepTags[k] = tags[k];
58853 var tagDiff = utilTagDiff(tags, keepTags);
58854 if (!tagDiff.length) return [];
58855 var fixID = tagDiff.length === 1 ? 'remove_tag' : 'remove_tags';
58856 return [new validationIssue({
58858 severity: 'warning',
58859 message: showMessage,
58860 reference: showReference,
58861 entityIds: [entity.id],
58862 dynamicFixes: function dynamicFixes() {
58863 return [new validationIssueFix({
58864 icon: 'iD-operation-delete',
58865 title: _t.html('issues.fix.' + fixID + '.title'),
58866 onClick: function onClick(context) {
58867 context.perform(doUpgrade, _t('issues.fix.upgrade_tags.annotation'));
58873 function doUpgrade(graph) {
58874 var currEntity = graph.hasEntity(entity.id);
58875 if (!currEntity) return graph;
58876 var newTags = Object.assign({}, currEntity.tags); // shallow copy
58878 tagDiff.forEach(function (diff) {
58879 if (diff.type === '-') {
58880 delete newTags[diff.key];
58881 } else if (diff.type === '+') {
58882 newTags[diff.key] = diff.newVal;
58885 return actionChangeTags(currEntity.id, newTags)(graph);
58888 function showMessage(context) {
58889 var currEntity = context.hasEntity(this.entityIds[0]);
58890 if (!currEntity) return '';
58891 return _t.html('issues.private_data.contact.message', {
58892 feature: utilDisplayLabel(currEntity, context.graph())
58896 function showReference(selection) {
58897 var enter = selection.selectAll('.issue-reference').data([0]).enter();
58898 enter.append('div').attr('class', 'issue-reference').html(_t.html('issues.private_data.reference'));
58899 enter.append('strong').html(_t.html('issues.suggested'));
58900 enter.append('table').attr('class', 'tagDiff-table').selectAll('.tagDiff-row').data(tagDiff).enter().append('tr').attr('class', 'tagDiff-row').append('td').attr('class', function (d) {
58901 var klass = d.type === '+' ? 'add' : 'remove';
58902 return 'tagDiff-cell tagDiff-cell-' + klass;
58903 }).html(function (d) {
58909 validation.type = type;
58913 function validationSuspiciousName() {
58914 var type = 'suspicious_name';
58915 var keysToTestForGenericValues = ['aerialway', 'aeroway', 'amenity', 'building', 'craft', 'highway', 'leisure', 'railway', 'man_made', 'office', 'shop', 'tourism', 'waterway'];
58916 var _waitingForNsi = false; // Attempt to match a generic record in the name-suggestion-index.
58918 function isGenericMatchInNsi(tags) {
58919 var nsi = services.nsi;
58922 _waitingForNsi = nsi.status() === 'loading';
58924 if (!_waitingForNsi) {
58925 return nsi.isGenericName(tags);
58930 } // Test if the name is just the key or tag value (e.g. "park")
58933 function nameMatchesRawTag(lowercaseName, tags) {
58934 for (var i = 0; i < keysToTestForGenericValues.length; i++) {
58935 var key = keysToTestForGenericValues[i];
58936 var val = tags[key];
58939 val = val.toLowerCase();
58941 if (key === lowercaseName || val === lowercaseName || key.replace(/\_/g, ' ') === lowercaseName || val.replace(/\_/g, ' ') === lowercaseName) {
58950 function isGenericName(name, tags) {
58951 name = name.toLowerCase();
58952 return nameMatchesRawTag(name, tags) || isGenericMatchInNsi(tags);
58955 function makeGenericNameIssue(entityId, nameKey, genericName, langCode) {
58956 return new validationIssue({
58958 subtype: 'generic_name',
58959 severity: 'warning',
58960 message: function message(context) {
58961 var entity = context.hasEntity(this.entityIds[0]);
58962 if (!entity) return '';
58963 var preset = _mainPresetIndex.match(entity, context.graph());
58964 var langName = langCode && _mainLocalizer.languageName(langCode);
58965 return _t.html('issues.generic_name.message' + (langName ? '_language' : ''), {
58966 feature: preset.name(),
58971 reference: showReference,
58972 entityIds: [entityId],
58973 hash: "".concat(nameKey, "=").concat(genericName),
58974 dynamicFixes: function dynamicFixes() {
58975 return [new validationIssueFix({
58976 icon: 'iD-operation-delete',
58977 title: _t.html('issues.fix.remove_the_name.title'),
58978 onClick: function onClick(context) {
58979 var entityId = this.issue.entityIds[0];
58980 var entity = context.entity(entityId);
58981 var tags = Object.assign({}, entity.tags); // shallow copy
58983 delete tags[nameKey];
58984 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_generic_name.annotation'));
58990 function showReference(selection) {
58991 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
58995 function makeIncorrectNameIssue(entityId, nameKey, incorrectName, langCode) {
58996 return new validationIssue({
58998 subtype: 'not_name',
58999 severity: 'warning',
59000 message: function message(context) {
59001 var entity = context.hasEntity(this.entityIds[0]);
59002 if (!entity) return '';
59003 var preset = _mainPresetIndex.match(entity, context.graph());
59004 var langName = langCode && _mainLocalizer.languageName(langCode);
59005 return _t.html('issues.incorrect_name.message' + (langName ? '_language' : ''), {
59006 feature: preset.name(),
59007 name: incorrectName,
59011 reference: showReference,
59012 entityIds: [entityId],
59013 hash: "".concat(nameKey, "=").concat(incorrectName),
59014 dynamicFixes: function dynamicFixes() {
59015 return [new validationIssueFix({
59016 icon: 'iD-operation-delete',
59017 title: _t.html('issues.fix.remove_the_name.title'),
59018 onClick: function onClick(context) {
59019 var entityId = this.issue.entityIds[0];
59020 var entity = context.entity(entityId);
59021 var tags = Object.assign({}, entity.tags); // shallow copy
59023 delete tags[nameKey];
59024 context.perform(actionChangeTags(entityId, tags), _t('issues.fix.remove_mistaken_name.annotation'));
59030 function showReference(selection) {
59031 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.generic_name.reference'));
59035 var validation = function checkGenericName(entity) {
59036 var tags = entity.tags; // a generic name is allowed if it's a known brand or entity
59038 var hasWikidata = !!tags.wikidata || !!tags['brand:wikidata'] || !!tags['operator:wikidata'];
59039 if (hasWikidata) return [];
59041 var notNames = (tags['not:name'] || '').split(';');
59043 for (var key in tags) {
59044 var m = key.match(/^name(?:(?::)([a-zA-Z_-]+))?$/);
59046 var langCode = m.length >= 2 ? m[1] : null;
59047 var value = tags[key];
59049 if (notNames.length) {
59050 for (var i in notNames) {
59051 var notName = notNames[i];
59053 if (notName && value === notName) {
59054 issues.push(makeIncorrectNameIssue(entity.id, key, value, langCode));
59060 if (isGenericName(value, tags)) {
59061 issues.provisional = _waitingForNsi; // retry later if we are waiting on NSI to finish loading
59063 issues.push(makeGenericNameIssue(entity.id, key, value, langCode));
59070 validation.type = type;
59074 function validationUnsquareWay(context) {
59075 var type = 'unsquare_way';
59076 var DEFAULT_DEG_THRESHOLD = 5; // see also issues.js
59077 // use looser epsilon for detection to reduce warnings of buildings that are essentially square already
59079 var epsilon = 0.05;
59080 var nodeThreshold = 10;
59082 function isBuilding(entity, graph) {
59083 if (entity.type !== 'way' || entity.geometry(graph) !== 'area') return false;
59084 return entity.tags.building && entity.tags.building !== 'no';
59087 var validation = function checkUnsquareWay(entity, graph) {
59088 if (!isBuilding(entity, graph)) return []; // don't flag ways marked as physically unsquare
59090 if (entity.tags.nonsquare === 'yes') return [];
59091 var isClosed = entity.isClosed();
59092 if (!isClosed) return []; // this building has bigger problems
59093 // don't flag ways with lots of nodes since they are likely detail-mapped
59095 var nodes = graph.childNodes(entity).slice(); // shallow copy
59097 if (nodes.length > nodeThreshold + 1) return []; // +1 because closing node appears twice
59098 // ignore if not all nodes are fully downloaded
59100 var osm = services.osm;
59101 if (!osm || nodes.some(function (node) {
59102 return !osm.isDataLoaded(node.loc);
59103 })) return []; // don't flag connected ways to avoid unresolvable unsquare loops
59105 var hasConnectedSquarableWays = nodes.some(function (node) {
59106 return graph.parentWays(node).some(function (way) {
59107 if (way.id === entity.id) return false;
59108 if (isBuilding(way, graph)) return true;
59109 return graph.parentRelations(way).some(function (parentRelation) {
59110 return parentRelation.isMultipolygon() && parentRelation.tags.building && parentRelation.tags.building !== 'no';
59114 if (hasConnectedSquarableWays) return []; // user-configurable square threshold
59116 var storedDegreeThreshold = corePreferences('validate-square-degrees');
59117 var degreeThreshold = isNaN(storedDegreeThreshold) ? DEFAULT_DEG_THRESHOLD : parseFloat(storedDegreeThreshold);
59118 var points = nodes.map(function (node) {
59119 return context.projection(node.loc);
59121 if (!geoOrthoCanOrthogonalize(points, isClosed, epsilon, degreeThreshold, true)) return [];
59122 var autoArgs; // don't allow autosquaring features linked to wikidata
59124 if (!entity.tags.wikidata) {
59125 // use same degree threshold as for detection
59126 var autoAction = actionOrthogonalize(entity.id, context.projection, undefined, degreeThreshold);
59127 autoAction.transitionable = false; // when autofixing, do it instantly
59129 autoArgs = [autoAction, _t('operations.orthogonalize.annotation.feature', {
59134 return [new validationIssue({
59136 subtype: 'building',
59137 severity: 'warning',
59138 message: function message(context) {
59139 var entity = context.hasEntity(this.entityIds[0]);
59140 return entity ? _t.html('issues.unsquare_way.message', {
59141 feature: utilDisplayLabel(entity, context.graph())
59144 reference: showReference,
59145 entityIds: [entity.id],
59146 hash: degreeThreshold,
59147 dynamicFixes: function dynamicFixes() {
59148 return [new validationIssueFix({
59149 icon: 'iD-operation-orthogonalize',
59150 title: _t.html('issues.fix.square_feature.title'),
59151 autoArgs: autoArgs,
59152 onClick: function onClick(context, completionHandler) {
59153 var entityId = this.issue.entityIds[0]; // use same degree threshold as for detection
59155 context.perform(actionOrthogonalize(entityId, context.projection, undefined, degreeThreshold), _t('operations.orthogonalize.annotation.feature', {
59157 })); // run after the squaring transition (currently 150ms)
59159 window.setTimeout(function () {
59160 completionHandler();
59165 new validationIssueFix({
59166 title: t.html('issues.fix.tag_as_unsquare.title'),
59167 onClick: function(context) {
59168 var entityId = this.issue.entityIds[0];
59169 var entity = context.entity(entityId);
59170 var tags = Object.assign({}, entity.tags); // shallow copy
59171 tags.nonsquare = 'yes';
59173 actionChangeTags(entityId, tags),
59174 t('issues.fix.tag_as_unsquare.annotation')
59183 function showReference(selection) {
59184 selection.selectAll('.issue-reference').data([0]).enter().append('div').attr('class', 'issue-reference').html(_t.html('issues.unsquare_way.buildings.reference'));
59188 validation.type = type;
59192 var Validations = /*#__PURE__*/Object.freeze({
59194 validationAlmostJunction: validationAlmostJunction,
59195 validationCloseNodes: validationCloseNodes,
59196 validationCrossingWays: validationCrossingWays,
59197 validationDisconnectedWay: validationDisconnectedWay,
59198 validationFormatting: validationFormatting,
59199 validationHelpRequest: validationHelpRequest,
59200 validationImpossibleOneway: validationImpossibleOneway,
59201 validationIncompatibleSource: validationIncompatibleSource,
59202 validationMaprules: validationMaprules,
59203 validationMismatchedGeometry: validationMismatchedGeometry,
59204 validationMissingRole: validationMissingRole,
59205 validationMissingTag: validationMissingTag,
59206 validationOutdatedTags: validationOutdatedTags,
59207 validationPrivateData: validationPrivateData,
59208 validationSuspiciousName: validationSuspiciousName,
59209 validationUnsquareWay: validationUnsquareWay
59212 function coreValidator(context) {
59215 var dispatch = dispatch$8('validated', 'focusedIssue');
59216 var validator = utilRebind({}, dispatch, 'on');
59218 var _disabledRules = {};
59220 var _ignoredIssueIDs = new Set();
59222 var _resolvedIssueIDs = new Set();
59224 var _baseCache = validationCache('base'); // issues before any user edits
59227 var _headCache = validationCache('head'); // issues after all user edits
59230 var _completeDiff = {}; // complete diff base -> head of what the user changed
59232 var _headIsCurrent = false;
59234 var _deferredRIC = new Set(); // Set( RequestIdleCallback handles )
59237 var _deferredST = new Set(); // Set( SetTimeout handles )
59240 var _headPromise; // Promise fulfilled when validation is performed up to headGraph snapshot
59243 var RETRY = 5000; // wait 5sec before revalidating provisional entities
59244 // Allow validation severity to be overridden by url queryparams...
59245 // See: https://github.com/openstreetmap/iD/pull/8243
59247 // Each param should contain a urlencoded comma separated list of
59248 // `type/subtype` rules. `*` may be used as a wildcard..
59250 // `validationError=disconnected_way/*`
59251 // `validationError=disconnected_way/highway`
59252 // `validationError=crossing_ways/bridge*`
59253 // `validationError=crossing_ways/bridge*,crossing_ways/tunnel*`
59255 var _errorOverrides = parseHashParam(context.initialHashParams.validationError);
59257 var _warningOverrides = parseHashParam(context.initialHashParams.validationWarning);
59259 var _disableOverrides = parseHashParam(context.initialHashParams.validationDisable); // `parseHashParam()` (private)
59260 // Checks hash parameters for severity overrides
59262 // `param` - a url hash parameter (`validationError`, `validationWarning`, or `validationDisable`)
59264 // Array of Objects like { type: RegExp, subtype: RegExp }
59268 function parseHashParam(param) {
59270 var rules = (param || '').split(',');
59271 rules.forEach(function (rule) {
59272 rule = rule.trim();
59273 var parts = rule.split('/', 2); // "type/subtype"
59275 var type = parts[0];
59276 var subtype = parts[1] || '*';
59277 if (!type || !subtype) return;
59279 type: makeRegExp(type),
59280 subtype: makeRegExp(subtype)
59285 function makeRegExp(str) {
59286 var escaped = str.replace(/[-\/\\^$+?.()|[\]{}]/g, '\\$&') // escape all reserved chars except for the '*'
59287 .replace(/\*/g, '.*'); // treat a '*' like '.*'
59289 return new RegExp('^' + escaped + '$');
59292 // Initialize the validator, called once on iD startup
59296 validator.init = function () {
59297 Object.values(Validations).forEach(function (validation) {
59298 if (typeof validation !== 'function') return;
59299 var fn = validation(context);
59303 var disabledRules = corePreferences('validate-disabledRules');
59305 if (disabledRules) {
59306 disabledRules.split(',').forEach(function (k) {
59307 return _disabledRules[k] = true;
59310 }; // `reset()` (private)
59311 // Cancels deferred work and resets all caches
59314 // `resetIgnored` - `true` to clear the list of user-ignored issues
59318 function reset(resetIgnored) {
59319 // cancel deferred work
59320 _deferredRIC.forEach(window.cancelIdleCallback);
59322 _deferredRIC.clear();
59324 _deferredST.forEach(window.clearTimeout);
59326 _deferredST.clear(); // empty queues and resolve any pending promise
59329 _baseCache.queue = [];
59330 _headCache.queue = [];
59331 processQueue(_headCache);
59332 processQueue(_baseCache); // clear caches
59334 if (resetIgnored) _ignoredIssueIDs.clear();
59336 _resolvedIssueIDs.clear();
59338 _baseCache = validationCache('base');
59339 _headCache = validationCache('head');
59340 _completeDiff = {};
59341 _headIsCurrent = false;
59343 // clear caches, called whenever iD resets after a save or switches sources
59344 // (clears out the _ignoredIssueIDs set also)
59348 validator.reset = function () {
59350 }; // `resetIgnoredIssues()`
59351 // clears out the _ignoredIssueIDs Set
59355 validator.resetIgnoredIssues = function () {
59356 _ignoredIssueIDs.clear();
59358 dispatch.call('validated'); // redraw UI
59359 }; // `revalidateUnsquare()`
59360 // Called whenever the user changes the unsquare threshold
59361 // It reruns just the "unsquare_way" validation on all buildings.
59365 validator.revalidateUnsquare = function () {
59366 revalidateUnsquare(_headCache);
59367 revalidateUnsquare(_baseCache);
59368 dispatch.call('validated');
59371 function revalidateUnsquare(cache) {
59372 var checkUnsquareWay = _rules.unsquare_way;
59373 if (!cache.graph || typeof checkUnsquareWay !== 'function') return; // uncache existing
59375 cache.uncacheIssuesOfType('unsquare_way');
59376 var buildings = context.history().tree().intersects(geoExtent([-180, -90], [180, 90]), cache.graph) // everywhere
59377 .filter(function (entity) {
59378 return entity.type === 'way' && entity.tags.building && entity.tags.building !== 'no';
59379 }); // rerun for all buildings
59381 buildings.forEach(function (entity) {
59382 var detected = checkUnsquareWay(entity, cache.graph);
59383 if (!detected.length) return;
59384 cache.cacheIssues(detected);
59387 // Gets all issues that match the given options
59388 // This is called by many other places
59391 // `options` Object like:
59393 // what: 'all', // 'all' or 'edited'
59394 // where: 'all', // 'all' or 'visible'
59395 // includeIgnored: false, // true, false, or 'only'
59396 // includeDisabledRules: false // true, false, or 'only'
59400 // An Array containing the issues
59404 validator.getIssues = function (options) {
59405 var opts = Object.assign({
59408 includeIgnored: false,
59409 includeDisabledRules: false
59411 var view = context.map().extent();
59412 var seen = new Set();
59413 var results = []; // collect head issues - present in the user edits
59415 if (_headCache.graph && _headCache.graph !== _baseCache.graph) {
59416 Object.values(_headCache.issuesByIssueID).forEach(function (issue) {
59417 // In the head cache, only count features that the user is responsible for - #8632
59418 // For example, a user can undo some work and an issue will still present in the
59419 // head graph, but we don't want to credit the user for causing that issue.
59420 var userModified = (issue.entityIds || []).some(function (id) {
59421 return _completeDiff.hasOwnProperty(id);
59423 if (opts.what === 'edited' && !userModified) return; // present in head but user didn't touch it
59425 if (!filter(issue)) return;
59426 seen.add(issue.id);
59427 results.push(issue);
59429 } // collect base issues - present before user edits
59432 if (opts.what === 'all') {
59433 Object.values(_baseCache.issuesByIssueID).forEach(function (issue) {
59434 if (!filter(issue)) return;
59435 seen.add(issue.id);
59436 results.push(issue);
59440 return results; // Filter the issue set to include only what the calling code wants to see.
59441 // Note that we use `context.graph()`/`context.hasEntity()` here, not `cache.graph`,
59442 // because that is the graph that the calling code will be using.
59444 function filter(issue) {
59445 if (!issue) return false;
59446 if (seen.has(issue.id)) return false;
59447 if (_resolvedIssueIDs.has(issue.id)) return false;
59448 if (opts.includeDisabledRules === 'only' && !_disabledRules[issue.type]) return false;
59449 if (!opts.includeDisabledRules && _disabledRules[issue.type]) return false;
59450 if (opts.includeIgnored === 'only' && !_ignoredIssueIDs.has(issue.id)) return false;
59451 if (!opts.includeIgnored && _ignoredIssueIDs.has(issue.id)) return false; // This issue may involve an entity that doesn't exist in context.graph()
59452 // This can happen because validation is async and rendering the issue lists is async.
59454 if ((issue.entityIds || []).some(function (id) {
59455 return !context.hasEntity(id);
59458 if (opts.where === 'visible') {
59459 var extent = issue.extent(context.graph());
59460 if (!view.intersects(extent)) return false;
59465 }; // `getResolvedIssues()`
59466 // Gets the issues that have been fixed by the user.
59468 // Resolved issues are tracked in the `_resolvedIssueIDs` Set,
59469 // and they should all be issues that exist in the _baseCache.
59472 // An Array containing the issues
59476 validator.getResolvedIssues = function () {
59477 return Array.from(_resolvedIssueIDs).map(function (issueID) {
59478 return _baseCache.issuesByIssueID[issueID];
59479 }).filter(Boolean);
59480 }; // `focusIssue()`
59481 // Adjusts the map to focus on the given issue.
59482 // (requires the issue to have a reasonable extent defined)
59485 // `issue` - the issue to focus on
59489 validator.focusIssue = function (issue) {
59490 // Note that we use `context.graph()`/`context.hasEntity()` here, not `cache.graph`,
59491 // because that is the graph that the calling code will be using.
59492 var graph = context.graph();
59494 var focusCenter; // Try to focus the map at the center of the issue..
59496 var issueExtent = issue.extent(graph);
59499 focusCenter = issueExtent.center();
59500 } // Try to select the first entity in the issue..
59503 if (issue.entityIds && issue.entityIds.length) {
59504 selectID = issue.entityIds[0]; // If a relation, focus on one of its members instead.
59505 // Otherwise we might be focusing on a part of map where the relation is not visible.
59507 if (selectID && selectID.charAt(0) === 'r') {
59509 var ids = utilEntityAndDeepMemberIDs([selectID], graph);
59510 var nodeID = ids.find(function (id) {
59511 return id.charAt(0) === 'n' && graph.hasEntity(id);
59515 // relation has no downloaded nodes to focus on
59516 var wayID = ids.find(function (id) {
59517 return id.charAt(0) === 'w' && graph.hasEntity(id);
59521 nodeID = graph.entity(wayID).first(); // focus on the first node of this way
59526 focusCenter = graph.entity(nodeID).loc;
59533 var setZoom = Math.max(context.map().zoom(), 19);
59534 context.map().unobscuredCenterZoomEase(focusCenter, setZoom);
59538 // Enter select mode
59539 window.setTimeout(function () {
59540 context.enter(modeSelect(context, [selectID]));
59541 dispatch.call('focusedIssue', _this, issue);
59542 }, 250); // after ease
59544 }; // `getIssuesBySeverity()`
59545 // Gets the issues then groups them by error/warning
59546 // (This just calls getIssues, then puts issues in groups)
59549 // `options` - (see `getIssues`)
59551 // Object result like:
59553 // error: Array of errors,
59554 // warning: Array of warnings
59559 validator.getIssuesBySeverity = function (options) {
59560 var groups = utilArrayGroupBy(validator.getIssues(options), 'severity');
59561 groups.error = groups.error || [];
59562 groups.warning = groups.warning || [];
59564 }; // `getEntityIssues()`
59565 // Gets the issues that the given entity IDs have in common, matching the given options
59566 // (This just calls getIssues, then filters for the given entity IDs)
59567 // The issues are sorted for relevance
59570 // `entityIDs` - Array or Set of entityIDs to get issues for
59571 // `options` - (see `getIssues`)
59573 // An Array containing the issues
59577 validator.getSharedEntityIssues = function (entityIDs, options) {
59578 var orderedIssueTypes = [// Show some issue types in a particular order:
59579 'missing_tag', 'missing_role', // - missing data first
59580 'outdated_tags', 'mismatched_geometry', // - identity issues
59581 'crossing_ways', 'almost_junction', // - geometry issues where fixing them might solve connectivity issues
59582 'disconnected_way', 'impossible_oneway' // - finally connectivity issues
59584 var allIssues = validator.getIssues(options);
59585 var forEntityIDs = new Set(entityIDs);
59586 return allIssues.filter(function (issue) {
59587 return (issue.entityIds || []).some(function (entityID) {
59588 return forEntityIDs.has(entityID);
59590 }).sort(function (issue1, issue2) {
59591 if (issue1.type === issue2.type) {
59592 // issues of the same type, sort deterministically
59593 return issue1.id < issue2.id ? -1 : 1;
59596 var index1 = orderedIssueTypes.indexOf(issue1.type);
59597 var index2 = orderedIssueTypes.indexOf(issue2.type);
59599 if (index1 !== -1 && index2 !== -1) {
59600 // both issue types have explicit sort orders
59601 return index1 - index2;
59602 } else if (index1 === -1 && index2 === -1) {
59603 // neither issue type has an explicit sort order, sort by type
59604 return issue1.type < issue2.type ? -1 : 1;
59606 // order explicit types before everything else
59607 return index1 !== -1 ? -1 : 1;
59610 }; // `getEntityIssues()`
59611 // Get an array of detected issues for the given entityID.
59612 // (This just calls getSharedEntityIssues for a single entity)
59615 // `entityID` - the entity ID to get the issues for
59616 // `options` - (see `getIssues`)
59618 // An Array containing the issues
59622 validator.getEntityIssues = function (entityID, options) {
59623 return validator.getSharedEntityIssues([entityID], options);
59624 }; // `getRuleKeys()`
59627 // An Array containing the rule keys
59631 validator.getRuleKeys = function () {
59632 return Object.keys(_rules);
59633 }; // `isRuleEnabled()`
59636 // `key` - the rule to check (e.g. 'crossing_ways')
59642 validator.isRuleEnabled = function (key) {
59643 return !_disabledRules[key];
59644 }; // `toggleRule()`
59645 // Toggles a single validation rule,
59646 // then reruns the validation so that the user sees something happen in the UI
59649 // `key` - the rule to toggle (e.g. 'crossing_ways')
59653 validator.toggleRule = function (key) {
59654 if (_disabledRules[key]) {
59655 delete _disabledRules[key];
59657 _disabledRules[key] = true;
59660 corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
59661 validator.validate();
59662 }; // `disableRules()`
59663 // Disables given validation rules,
59664 // then reruns the validation so that the user sees something happen in the UI
59667 // `keys` - Array or Set containing rule keys to disable
59671 validator.disableRules = function (keys) {
59672 _disabledRules = {};
59673 keys.forEach(function (k) {
59674 return _disabledRules[k] = true;
59676 corePreferences('validate-disabledRules', Object.keys(_disabledRules).join(','));
59677 validator.validate();
59678 }; // `ignoreIssue()`
59679 // Don't show the given issue in lists
59682 // `issueID` - the issueID
59686 validator.ignoreIssue = function (issueID) {
59687 _ignoredIssueIDs.add(issueID);
59689 // Validates anything that has changed in the head graph since the last time it was run.
59690 // (head graph contains user's edits)
59693 // A Promise fulfilled when the validation has completed and then dispatches a `validated` event.
59694 // This may take time but happen in the background during browser idle time.
59698 validator.validate = function () {
59699 // Make sure the caches have graphs assigned to them.
59700 // (we don't do this in `reset` because context is still resetting things and `history.base()` is unstable then)
59701 var baseGraph = context.history().base();
59702 if (!_headCache.graph) _headCache.graph = baseGraph;
59703 if (!_baseCache.graph) _baseCache.graph = baseGraph;
59704 var prevGraph = _headCache.graph;
59705 var currGraph = context.graph();
59707 if (currGraph === prevGraph) {
59708 // _headCache.graph is current - we are caught up
59709 _headIsCurrent = true;
59710 dispatch.call('validated');
59711 return Promise.resolve();
59714 if (_headPromise) {
59715 // Validation already in process, but we aren't caught up to current
59716 _headIsCurrent = false; // We will need to catch up after the validation promise fulfills
59718 return _headPromise;
59719 } // If we get here, its time to start validating stuff.
59722 _headCache.graph = currGraph; // take snapshot
59724 _completeDiff = context.history().difference().complete();
59725 var incrementalDiff = coreDifference(prevGraph, currGraph);
59726 var entityIDs = Object.keys(incrementalDiff.complete());
59727 entityIDs = _headCache.withAllRelatedEntities(entityIDs); // expand set
59729 if (!entityIDs.size) {
59730 dispatch.call('validated');
59731 return Promise.resolve();
59734 _headPromise = validateEntitiesAsync(entityIDs, _headCache).then(function () {
59735 return updateResolvedIssues(entityIDs);
59736 }).then(function () {
59737 return dispatch.call('validated');
59738 })["catch"](function () {
59740 }).then(function () {
59741 _headPromise = null;
59743 if (!_headIsCurrent) {
59744 validator.validate(); // run it again to catch up to current graph
59747 return _headPromise;
59748 }; // register event handlers:
59749 // WHEN TO RUN VALIDATION:
59750 // When history changes:
59753 context.history().on('restore.validator', validator.validate) // on restore saved history
59754 .on('undone.validator', validator.validate) // on undo
59755 .on('redone.validator', validator.validate) // on redo
59756 .on('reset.validator', function () {
59757 // on history reset - happens after save, or enter/exit walkthrough
59758 reset(false); // cached issues aren't valid any longer if the history has been reset
59760 validator.validate();
59761 }); // but not on 'change' (e.g. while drawing)
59762 // When user changes editing modes (to catch recent changes e.g. drawing)
59764 context.on('exit.validator', validator.validate); // When merging fetched data, validate base graph:
59766 context.history().on('merge.validator', function (entities) {
59767 if (!entities) return; // Make sure the caches have graphs assigned to them.
59768 // (we don't do this in `reset` because context is still resetting things and `history.base()` is unstable then)
59770 var baseGraph = context.history().base();
59771 if (!_headCache.graph) _headCache.graph = baseGraph;
59772 if (!_baseCache.graph) _baseCache.graph = baseGraph;
59773 var entityIDs = entities.map(function (entity) {
59776 entityIDs = _baseCache.withAllRelatedEntities(entityIDs); // expand set
59778 validateEntitiesAsync(entityIDs, _baseCache);
59779 }); // `validateEntity()` (private)
59780 // Runs all validation rules on a single entity.
59781 // Some things to note:
59782 // - Graph is passed in from whenever the validation was started. Validators shouldn't use
59783 // `context.graph()` because this all happens async, and the graph might have changed
59784 // (for example, nodes getting deleted before the validation can run)
59785 // - Validator functions may still be waiting on something and return a "provisional" result.
59786 // In this situation, we will schedule to revalidate the entity sometime later.
59789 // `entity` - The entity
59790 // `graph` - graph containing the entity
59793 // Object result like:
59795 // issues: Array of detected issues
59796 // provisional: `true` if provisional result, `false` if final result
59800 function validateEntity(entity, graph) {
59805 Object.keys(_rules).forEach(runValidation); // run all rules
59807 return result; // runs validation and appends resulting issues
59809 function runValidation(key) {
59810 var fn = _rules[key];
59812 if (typeof fn !== 'function') {
59813 console.error('no such validation rule = ' + key); // eslint-disable-line no-console
59818 var detected = fn(entity, graph);
59820 if (detected.provisional) {
59821 // this validation should be run again later
59822 result.provisional = true;
59825 detected = detected.filter(applySeverityOverrides);
59826 result.issues = result.issues.concat(detected); // If there are any override rules that match the issue type/subtype,
59827 // adjust severity (or disable it) and keep/discard as quickly as possible.
59829 function applySeverityOverrides(issue) {
59830 var type = issue.type;
59831 var subtype = issue.subtype || '';
59834 for (i = 0; i < _errorOverrides.length; i++) {
59835 if (_errorOverrides[i].type.test(type) && _errorOverrides[i].subtype.test(subtype)) {
59836 issue.severity = 'error';
59841 for (i = 0; i < _warningOverrides.length; i++) {
59842 if (_warningOverrides[i].type.test(type) && _warningOverrides[i].subtype.test(subtype)) {
59843 issue.severity = 'warning';
59848 for (i = 0; i < _disableOverrides.length; i++) {
59849 if (_disableOverrides[i].type.test(type) && _disableOverrides[i].subtype.test(subtype)) {
59857 } // `updateResolvedIssues()` (private)
59858 // Determine if any issues were resolved for the given entities.
59859 // This is called by `validate()` after validation of the head graph
59861 // Give the user credit for fixing an issue if:
59862 // - the issue is in the base cache
59863 // - the issue is not in the head cache
59864 // - the user did something to one of the entities involved in the issue
59867 // `entityIDs` - Array or Set containing entity IDs.
59871 function updateResolvedIssues(entityIDs) {
59872 entityIDs.forEach(function (entityID) {
59873 var baseIssues = _baseCache.issuesByEntityID[entityID];
59874 if (!baseIssues) return;
59875 baseIssues.forEach(function (issueID) {
59876 // Check if the user did something to one of the entities involved in this issue.
59877 // (This issue could involve multiple entities, e.g. disconnected routable features)
59878 var issue = _baseCache.issuesByIssueID[issueID];
59879 var userModified = (issue.entityIds || []).some(function (id) {
59880 return _completeDiff.hasOwnProperty(id);
59883 if (userModified && !_headCache.issuesByIssueID[issueID]) {
59884 // issue seems fixed
59885 _resolvedIssueIDs.add(issueID);
59887 // issue still not resolved
59888 _resolvedIssueIDs["delete"](issueID); // (did undo, or possibly fixed and then re-caused the issue)
59893 } // `validateEntitiesAsync()` (private)
59894 // Schedule validation for many entities.
59897 // `entityIDs` - Array or Set containing entityIDs.
59898 // `graph` - the graph to validate that contains those entities
59899 // `cache` - the cache to store results in (_headCache or _baseCache)
59902 // A Promise fulfilled when the validation has completed.
59903 // This may take time but happen in the background during browser idle time.
59907 function validateEntitiesAsync(entityIDs, cache) {
59908 // Enqueue the work
59909 var jobs = Array.from(entityIDs).map(function (entityID) {
59910 if (cache.queuedEntityIDs.has(entityID)) return null; // queued already
59912 cache.queuedEntityIDs.add(entityID); // Clear caches for existing issues related to this entity
59914 cache.uncacheEntityID(entityID);
59915 return function () {
59916 cache.queuedEntityIDs["delete"](entityID);
59917 var graph = cache.graph;
59918 if (!graph) return; // was reset?
59920 var entity = graph.hasEntity(entityID); // Sanity check: don't validate deleted entities
59922 if (!entity) return; // detect new issues and update caches
59924 var result = validateEntity(entity, graph);
59926 if (result.provisional) {
59927 // provisional result
59928 cache.provisionalEntityIDs.add(entityID); // we'll need to revalidate this entity again later
59931 cache.cacheIssues(result.issues); // update cache
59933 }).filter(Boolean); // Perform the work in chunks.
59934 // Because this will happen during idle callbacks, we want to choose a chunk size
59935 // that won't make the browser stutter too badly.
59937 cache.queue = cache.queue.concat(utilArrayChunk(jobs, 100)); // Perform the work
59939 if (cache.queuePromise) return cache.queuePromise;
59940 cache.queuePromise = processQueue(cache).then(function () {
59941 return revalidateProvisionalEntities(cache);
59942 })["catch"](function () {
59944 })["finally"](function () {
59945 return cache.queuePromise = null;
59947 return cache.queuePromise;
59948 } // `revalidateProvisionalEntities()` (private)
59949 // Sometimes a validator will return a "provisional" result.
59950 // In this situation, we'll need to revalidate the entity later.
59951 // This function waits a delay, then places them back into the validation queue.
59954 // `cache` - The cache (_headCache or _baseCache)
59958 function revalidateProvisionalEntities(cache) {
59959 if (!cache.provisionalEntityIDs.size) return; // nothing to do
59961 var handle = window.setTimeout(function () {
59962 _deferredST["delete"](handle);
59964 if (!cache.provisionalEntityIDs.size) return; // nothing to do
59966 validateEntitiesAsync(Array.from(cache.provisionalEntityIDs), cache);
59969 _deferredST.add(handle);
59970 } // `processQueue(queue)` (private)
59971 // Process the next chunk of deferred validation work
59974 // `cache` - The cache (_headCache or _baseCache)
59977 // A Promise fulfilled when the validation has completed.
59978 // This may take time but happen in the background during browser idle time.
59982 function processQueue(cache) {
59983 // console.log(`${cache.which} queue length ${cache.queue.length}`);
59984 if (!cache.queue.length) return Promise.resolve(); // we're done
59986 var chunk = cache.queue.pop();
59987 return new Promise(function (resolvePromise) {
59988 var handle = window.requestIdleCallback(function () {
59989 _deferredRIC["delete"](handle); // const t0 = performance.now();
59992 chunk.forEach(function (job) {
59994 }); // const t1 = performance.now();
59995 // console.log('chunk processed in ' + (t1 - t0) + ' ms');
60000 _deferredRIC.add(handle);
60001 }).then(function () {
60002 // dispatch an event sometimes to redraw various UI things
60003 if (cache.queue.length % 25 === 0) dispatch.call('validated');
60004 }).then(function () {
60005 return processQueue(cache);
60010 } // `validationCache()` (private)
60011 // Creates a cache to store validation state
60012 // We create 2 of these:
60013 // `_baseCache` for validation on the base graph (unedited)
60014 // `_headCache` for validation on the head graph (user edits applied)
60017 // `which` - just a String 'base' or 'head' to keep track of it
60020 function validationCache(which) {
60025 queuePromise: null,
60026 queuedEntityIDs: new Set(),
60027 provisionalEntityIDs: new Set(),
60028 issuesByIssueID: {},
60029 // issue.id -> issue
60030 issuesByEntityID: {} // entity.id -> Set(issue.id)
60034 cache.cacheIssue = function (issue) {
60035 (issue.entityIds || []).forEach(function (entityID) {
60036 if (!cache.issuesByEntityID[entityID]) {
60037 cache.issuesByEntityID[entityID] = new Set();
60040 cache.issuesByEntityID[entityID].add(issue.id);
60042 cache.issuesByIssueID[issue.id] = issue;
60045 cache.uncacheIssue = function (issue) {
60046 (issue.entityIds || []).forEach(function (entityID) {
60047 if (cache.issuesByEntityID[entityID]) {
60048 cache.issuesByEntityID[entityID]["delete"](issue.id);
60051 delete cache.issuesByIssueID[issue.id];
60054 cache.cacheIssues = function (issues) {
60055 issues.forEach(cache.cacheIssue);
60058 cache.uncacheIssues = function (issues) {
60059 issues.forEach(cache.uncacheIssue);
60062 cache.uncacheIssuesOfType = function (type) {
60063 var issuesOfType = Object.values(cache.issuesByIssueID).filter(function (issue) {
60064 return issue.type === type;
60066 cache.uncacheIssues(issuesOfType);
60067 }; // Remove a single entity and all its related issues from the caches
60070 cache.uncacheEntityID = function (entityID) {
60071 var entityIssueIDs = cache.issuesByEntityID[entityID];
60073 if (entityIssueIDs) {
60074 entityIssueIDs.forEach(function (issueID) {
60075 var issue = cache.issuesByIssueID[issueID];
60078 cache.uncacheIssue(issue);
60080 // shouldn't happen, clean up
60081 delete cache.issuesByIssueID[issueID];
60086 delete cache.issuesByEntityID[entityID];
60087 cache.provisionalEntityIDs["delete"](entityID);
60088 }; // Return the expandeded set of entityIDs related to issues for the given entityIDs
60091 // `entityIDs` - Array or Set containing entityIDs.
60095 cache.withAllRelatedEntities = function (entityIDs) {
60096 var result = new Set();
60097 (entityIDs || []).forEach(function (entityID) {
60098 result.add(entityID); // include self
60100 var entityIssueIDs = cache.issuesByEntityID[entityID];
60102 if (entityIssueIDs) {
60103 entityIssueIDs.forEach(function (issueID) {
60104 var issue = cache.issuesByIssueID[issueID];
60107 (issue.entityIds || []).forEach(function (relatedID) {
60108 return result.add(relatedID);
60111 // shouldn't happen, clean up
60112 delete cache.issuesByIssueID[issueID];
60123 function coreUploader(context) {
60124 var dispatch = dispatch$8( // Start and end events are dispatched exactly once each per legitimate outside call to `save`
60125 'saveStarted', // dispatched as soon as a call to `save` has been deemed legitimate
60126 'saveEnded', // dispatched after the result event has been dispatched
60127 'willAttemptUpload', // dispatched before the actual upload call occurs, if it will
60128 'progressChanged', // Each save results in one of these outcomes:
60129 'resultNoChanges', // upload wasn't attempted since there were no edits
60130 'resultErrors', // upload failed due to errors
60131 'resultConflicts', // upload failed due to data conflicts
60132 'resultSuccess' // upload completed without errors
60134 var _isSaving = false;
60135 var _conflicts = [];
60140 var _discardTags = {};
60141 _mainFileFetcher.get('discarded').then(function (d) {
60143 })["catch"](function () {
60146 var uploader = utilRebind({}, dispatch, 'on');
60148 uploader.isSaving = function () {
60152 uploader.save = function (changeset, tryAgain, checkConflicts) {
60153 // Guard against accidentally entering save code twice - #4641
60154 if (_isSaving && !tryAgain) {
60158 var osm = context.connection();
60159 if (!osm) return; // If user somehow got logged out mid-save, try to reauthenticate..
60160 // This can happen if they were logged in from before, but the tokens are no longer valid.
60162 if (!osm.authenticated()) {
60163 osm.authenticate(function (err) {
60165 uploader.save(changeset, tryAgain, checkConflicts); // continue where we left off..
60173 dispatch.call('saveStarted', this);
60176 var history = context.history();
60178 _errors = []; // Store original changes, in case user wants to download them as an .osc file
60180 _origChanges = history.changes(actionDiscardTags(history.difference(), _discardTags)); // First time, `history.perform` a no-op action.
60181 // Any conflict resolutions will be done as `history.replace`
60182 // Remember to pop this later if needed
60185 history.perform(actionNoop());
60186 } // Attempt a fast upload.. If there are conflicts, re-enter with `checkConflicts = true`
60189 if (!checkConflicts) {
60190 upload(changeset); // Do the full (slow) conflict check..
60192 performFullConflictCheck(changeset);
60196 function performFullConflictCheck(changeset) {
60197 var osm = context.connection();
60199 var history = context.history();
60200 var localGraph = context.graph();
60201 var remoteGraph = coreGraph(history.base(), true);
60202 var summary = history.difference().summary();
60205 for (var i = 0; i < summary.length; i++) {
60206 var item = summary[i];
60208 if (item.changeType === 'modified') {
60209 _toCheck.push(item.entity.id);
60213 var _toLoad = withChildNodes(_toCheck, localGraph);
60216 var _toLoadCount = 0;
60217 var _toLoadTotal = _toLoad.length;
60219 if (_toCheck.length) {
60220 dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
60222 _toLoad.forEach(function (id) {
60223 _loaded[id] = false;
60226 osm.loadMultiple(_toLoad, loaded);
60233 function withChildNodes(ids, graph) {
60234 var s = new Set(ids);
60235 ids.forEach(function (id) {
60236 var entity = graph.entity(id);
60237 if (entity.type !== 'way') return;
60238 graph.childNodes(entity).forEach(function (child) {
60239 if (child.version !== undefined) {
60244 return Array.from(s);
60245 } // Reload modified entities into an alternate graph and check for conflicts..
60248 function loaded(err, result) {
60249 if (_errors.length) return;
60253 msg: err.message || err.responseText,
60254 details: [_t('save.status_code', {
60259 didResultInErrors();
60262 result.data.forEach(function (entity) {
60263 remoteGraph.replace(entity);
60264 _loaded[entity.id] = true;
60265 _toLoad = _toLoad.filter(function (val) {
60266 return val !== entity.id;
60268 if (!entity.visible) return; // Because loadMultiple doesn't download /full like loadEntity,
60269 // need to also load children that aren't already being checked..
60273 if (entity.type === 'way') {
60274 for (i = 0; i < entity.nodes.length; i++) {
60275 id = entity.nodes[i];
60277 if (_loaded[id] === undefined) {
60278 _loaded[id] = false;
60282 } else if (entity.type === 'relation' && entity.isMultipolygon()) {
60283 for (i = 0; i < entity.members.length; i++) {
60284 id = entity.members[i].id;
60286 if (_loaded[id] === undefined) {
60287 _loaded[id] = false;
60293 _toLoadCount += result.data.length;
60294 _toLoadTotal += loadMore.length;
60295 dispatch.call('progressChanged', this, _toLoadCount, _toLoadTotal);
60297 if (loadMore.length) {
60298 _toLoad.push.apply(_toLoad, loadMore);
60300 osm.loadMultiple(loadMore, loaded);
60303 if (!_toLoad.length) {
60310 function detectConflicts() {
60311 function choice(id, text, _action) {
60315 action: function action() {
60316 history.replace(_action);
60321 function formatUser(d) {
60322 return '<a href="' + osm.userURL(d) + '" target="_blank">' + d + '</a>';
60325 function entityName(entity) {
60326 return utilDisplayName(entity) || utilDisplayType(entity.id) + ' ' + entity.id;
60329 function sameVersions(local, remote) {
60330 if (local.version !== remote.version) return false;
60332 if (local.type === 'way') {
60333 var children = utilArrayUnion(local.nodes, remote.nodes);
60335 for (var i = 0; i < children.length; i++) {
60336 var a = localGraph.hasEntity(children[i]);
60337 var b = remoteGraph.hasEntity(children[i]);
60338 if (a && b && a.version !== b.version) return false;
60345 _toCheck.forEach(function (id) {
60346 var local = localGraph.entity(id);
60347 var remote = remoteGraph.entity(id);
60348 if (sameVersions(local, remote)) return;
60349 var merge = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags, formatUser);
60350 history.replace(merge);
60351 var mergeConflicts = merge.conflicts();
60352 if (!mergeConflicts.length) return; // merged safely
60354 var forceLocal = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_local');
60355 var forceRemote = actionMergeRemoteChanges(id, localGraph, remoteGraph, _discardTags).withOption('force_remote');
60356 var keepMine = _t('save.conflict.' + (remote.visible ? 'keep_local' : 'restore'));
60357 var keepTheirs = _t('save.conflict.' + (remote.visible ? 'keep_remote' : 'delete'));
60361 name: entityName(local),
60362 details: mergeConflicts,
60364 choices: [choice(id, keepMine, forceLocal), choice(id, keepTheirs, forceRemote)]
60370 function upload(changeset) {
60371 var osm = context.connection();
60375 msg: 'No OSM Service'
60379 if (_conflicts.length) {
60380 didResultInConflicts(changeset);
60381 } else if (_errors.length) {
60382 didResultInErrors();
60384 var history = context.history();
60385 var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
60387 if (changes.modified.length || changes.created.length || changes.deleted.length) {
60388 dispatch.call('willAttemptUpload', this);
60389 osm.putChangeset(changeset, changes, uploadCallback);
60391 // changes were insignificant or reverted by user
60392 didResultInNoChanges();
60397 function uploadCallback(err, changeset) {
60399 if (err.status === 409) {
60401 uploader.save(changeset, true, true); // tryAgain = true, checkConflicts = true
60404 msg: err.message || err.responseText,
60405 details: [_t('save.status_code', {
60410 didResultInErrors();
60413 didResultInSuccess(changeset);
60417 function didResultInNoChanges() {
60418 dispatch.call('resultNoChanges', this);
60420 context.flush(); // reset iD
60423 function didResultInErrors() {
60424 context.history().pop();
60425 dispatch.call('resultErrors', this, _errors);
60429 function didResultInConflicts(changeset) {
60430 _conflicts.sort(function (a, b) {
60431 return b.id.localeCompare(a.id);
60434 dispatch.call('resultConflicts', this, changeset, _conflicts, _origChanges);
60438 function didResultInSuccess(changeset) {
60439 // delete the edit stack cached to local storage
60440 context.history().clearSaved();
60441 dispatch.call('resultSuccess', this, changeset); // Add delay to allow for postgres replication #1646 #2678
60443 window.setTimeout(function () {
60445 context.flush(); // reset iD
60449 function endSave() {
60451 dispatch.call('saveEnded', this);
60454 uploader.cancelConflictResolution = function () {
60455 context.history().pop();
60458 uploader.processResolvedConflicts = function (changeset) {
60459 var history = context.history();
60461 for (var i = 0; i < _conflicts.length; i++) {
60462 if (_conflicts[i].chosen === 1) {
60463 // user chose "use theirs"
60464 var entity = context.hasEntity(_conflicts[i].id);
60466 if (entity && entity.type === 'way') {
60467 var children = utilArrayUniq(entity.nodes);
60469 for (var j = 0; j < children.length; j++) {
60470 history.replace(actionRevert(children[j]));
60474 history.replace(actionRevert(_conflicts[i].id));
60478 uploader.save(changeset, true, false); // tryAgain = true, checkConflicts = false
60481 uploader.reset = function () {};
60487 var fails = fails$N;
60488 var expm1 = mathExpm1;
60490 var abs = Math.abs;
60491 var exp = Math.exp;
60494 var FORCED = fails(function () {
60495 // eslint-disable-next-line es/no-math-sinh -- required for testing
60496 return Math.sinh(-2e-17) != -2e-17;
60499 // `Math.sinh` method
60500 // https://tc39.es/ecma262/#sec-math.sinh
60501 // V8 near Chromium 38 has a problem with very small numbers
60502 $$3({ target: 'Math', stat: true, forced: FORCED }, {
60503 sinh: function sinh(x) {
60504 return abs(x = +x) < 1 ? (expm1(x) - expm1(-x)) / 2 : (exp(x - 1) - exp(-x - 1)) * (E / 2);
60508 var isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2; // listen for DPI change, e.g. when dragging a browser window from a retina to non-retina screen
60510 window.matchMedia("\n (-webkit-min-device-pixel-ratio: 2), /* Safari */\n (min-resolution: 2dppx), /* standard */\n (min-resolution: 192dpi) /* fallback */\n ").addListener(function () {
60511 isRetina = window.devicePixelRatio && window.devicePixelRatio >= 2;
60514 function localeDateString(s) {
60515 if (!s) return null;
60521 var d = new Date(s);
60522 if (isNaN(d.getTime())) return null;
60523 return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
60526 function vintageRange(vintage) {
60529 if (vintage.start || vintage.end) {
60530 s = vintage.start || '?';
60532 if (vintage.start !== vintage.end) {
60533 s += ' - ' + (vintage.end || '?');
60540 function rendererBackgroundSource(data) {
60541 var source = Object.assign({}, data); // shallow copy
60543 var _offset = [0, 0];
60544 var _name = source.name;
60545 var _description = source.description;
60547 var _best = !!source.best;
60549 var _template = source.encrypted ? utilAesDecrypt(source.template) : source.template;
60551 source.tileSize = data.tileSize || 256;
60552 source.zoomExtent = data.zoomExtent || [0, 22];
60553 source.overzoom = data.overzoom !== false;
60555 source.offset = function (val) {
60556 if (!arguments.length) return _offset;
60561 source.nudge = function (val, zoomlevel) {
60562 _offset[0] += val[0] / Math.pow(2, zoomlevel);
60563 _offset[1] += val[1] / Math.pow(2, zoomlevel);
60567 source.name = function () {
60568 var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60569 return _t('imagery.' + id_safe + '.name', {
60574 source.label = function () {
60575 var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60576 return _t.html('imagery.' + id_safe + '.name', {
60581 source.description = function () {
60582 var id_safe = source.id.replace(/\./g, '<TX_DOT>');
60583 return _t.html('imagery.' + id_safe + '.description', {
60584 "default": _description
60588 source.best = function () {
60592 source.area = function () {
60593 if (!data.polygon) return Number.MAX_VALUE; // worldwide
60595 var area = d3_geoArea({
60596 type: 'MultiPolygon',
60597 coordinates: [data.polygon]
60599 return isNaN(area) ? 0 : area;
60602 source.imageryUsed = function () {
60603 return _name || source.id;
60606 source.template = function (val) {
60607 if (!arguments.length) return _template;
60609 if (source.id === 'custom' || source.id === 'Bing') {
60616 source.url = function (coord) {
60617 var result = _template;
60618 if (result === '') return result; // source 'none'
60619 // Guess a type based on the tokens present in the template
60620 // (This is for 'custom' source, where we don't know)
60622 if (!source.type) {
60623 if (/SERVICE=WMS|\{(proj|wkid|bbox)\}/.test(_template)) {
60624 source.type = 'wms';
60625 source.projection = 'EPSG:3857'; // guess
60626 } else if (/\{(x|y)\}/.test(_template)) {
60627 source.type = 'tms';
60628 } else if (/\{u\}/.test(_template)) {
60629 source.type = 'bing';
60633 if (source.type === 'wms') {
60634 var tileToProjectedCoords = function tileToProjectedCoords(x, y, z) {
60635 //polyfill for IE11, PhantomJS
60636 var sinh = Math.sinh || function (x) {
60637 var y = Math.exp(x);
60638 return (y - 1 / y) / 2;
60641 var zoomSize = Math.pow(2, z);
60642 var lon = x / zoomSize * Math.PI * 2 - Math.PI;
60643 var lat = Math.atan(sinh(Math.PI * (1 - 2 * y / zoomSize)));
60645 switch (source.projection) {
60648 x: lon * 180 / Math.PI,
60649 y: lat * 180 / Math.PI
60653 // EPSG:3857 and synonyms
60654 var mercCoords = mercatorRaw(lon, lat);
60656 x: 20037508.34 / Math.PI * mercCoords[0],
60657 y: 20037508.34 / Math.PI * mercCoords[1]
60662 var tileSize = source.tileSize;
60663 var projection = source.projection;
60664 var minXmaxY = tileToProjectedCoords(coord[0], coord[1], coord[2]);
60665 var maxXminY = tileToProjectedCoords(coord[0] + 1, coord[1] + 1, coord[2]);
60666 result = result.replace(/\{(\w+)\}/g, function (token, key) {
60676 return projection.replace(/^EPSG:/, '');
60679 // WMS 1.3 flips x/y for some coordinate systems including EPSG:4326 - #7557
60680 if (projection === 'EPSG:4326' && // The CRS parameter implies version 1.3 (prior versions use SRS)
60681 /VERSION=1.3|CRS={proj}/.test(source.template().toUpperCase())) {
60682 return maxXminY.y + ',' + minXmaxY.x + ',' + minXmaxY.y + ',' + maxXminY.x;
60684 return minXmaxY.x + ',' + maxXminY.y + ',' + maxXminY.x + ',' + minXmaxY.y;
60703 } else if (source.type === 'tms') {
60704 result = result.replace('{x}', coord[0]).replace('{y}', coord[1]) // TMS-flipped y coordinate
60705 .replace(/\{[t-]y\}/, Math.pow(2, coord[2]) - coord[1] - 1).replace(/\{z(oom)?\}/, coord[2]) // only fetch retina tiles for retina screens
60706 .replace(/\{@2x\}|\{r\}/, isRetina ? '@2x' : '');
60707 } else if (source.type === 'bing') {
60708 result = result.replace('{u}', function () {
60711 for (var zoom = coord[2]; zoom > 0; zoom--) {
60713 var mask = 1 << zoom - 1;
60714 if ((coord[0] & mask) !== 0) b++;
60715 if ((coord[1] & mask) !== 0) b += 2;
60721 } // these apply to any type..
60724 result = result.replace(/\{switch:([^}]+)\}/, function (s, r) {
60725 var subdomains = r.split(',');
60726 return subdomains[(coord[0] + coord[1]) % subdomains.length];
60731 source.validZoom = function (z) {
60732 return source.zoomExtent[0] <= z && (source.overzoom || source.zoomExtent[1] > z);
60735 source.isLocatorOverlay = function () {
60736 return source.id === 'mapbox_locator_overlay';
60738 /* hides a source from the list, but leaves it available for use */
60741 source.isHidden = function () {
60742 return source.id === 'DigitalGlobe-Premium-vintage' || source.id === 'DigitalGlobe-Standard-vintage';
60745 source.copyrightNotices = function () {};
60747 source.getMetadata = function (center, tileCoord, callback) {
60749 start: localeDateString(source.startDate),
60750 end: localeDateString(source.endDate)
60752 vintage.range = vintageRange(vintage);
60756 callback(null, metadata);
60762 rendererBackgroundSource.Bing = function (data, dispatch) {
60763 // https://docs.microsoft.com/en-us/bingmaps/rest-services/imagery/get-imagery-metadata
60764 // https://docs.microsoft.com/en-us/bingmaps/rest-services/directly-accessing-the-bing-maps-tiles
60765 //fallback url template
60766 data.template = 'https://ecn.t{switch:0,1,2,3}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&n=z';
60767 var bing = rendererBackgroundSource(data); //var key = 'Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU'; // P2, JOSM, etc
60769 var key = 'Ak5oTE46TUbjRp08OFVcGpkARErDobfpuyNKa-W2mQ8wbt1K1KL8p1bIRwWwcF-Q'; // iD
60772 missing tile image strictness param (n=)
60773 • n=f -> (Fail) returns a 404
60774 • n=z -> (Empty) returns a 200 with 0 bytes (no content)
60775 • n=t -> (Transparent) returns a 200 with a transparent (png) tile
60778 var strictParam = 'n';
60779 var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial?include=ImageryProviders&uriScheme=https&key=' + key;
60782 var providers = [];
60783 d3_json(url).then(function (json) {
60784 var imageryResource = json.resourceSets[0].resources[0]; //retrieve and prepare up to date imagery template
60786 var template = imageryResource.imageUrl; //https://ecn.{subdomain}.tiles.virtualearth.net/tiles/a{quadkey}.jpeg?g=10339
60788 var subDomains = imageryResource.imageUrlSubdomains; //["t0, t1, t2, t3"]
60790 var subDomainNumbers = subDomains.map(function (subDomain) {
60791 return subDomain.substring(1);
60793 template = template.replace('{subdomain}', "t{switch:".concat(subDomainNumbers, "}")).replace('{quadkey}', '{u}');
60795 if (!new URLSearchParams(template).has(strictParam)) {
60796 template += "&".concat(strictParam, "=z");
60799 bing.template(template);
60800 providers = imageryResource.imageryProviders.map(function (provider) {
60802 attribution: provider.attribution,
60803 areas: provider.coverageAreas.map(function (area) {
60805 zoom: [area.zoomMin, area.zoomMax],
60806 extent: geoExtent([area.bbox[1], area.bbox[0]], [area.bbox[3], area.bbox[2]])
60811 dispatch.call('change');
60812 })["catch"](function () {
60816 bing.copyrightNotices = function (zoom, extent) {
60817 zoom = Math.min(zoom, 21);
60818 return providers.filter(function (provider) {
60819 return provider.areas.some(function (area) {
60820 return extent.intersects(area.extent) && area.zoom[0] <= zoom && area.zoom[1] >= zoom;
60822 }).map(function (provider) {
60823 return provider.attribution;
60827 bing.getMetadata = function (center, tileCoord, callback) {
60828 var tileID = tileCoord.slice(0, 3).join('/');
60829 var zoom = Math.min(tileCoord[2], 21);
60830 var centerPoint = center[1] + ',' + center[0]; // lat,lng
60832 var url = 'https://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/' + centerPoint + '?zl=' + zoom + '&key=' + key;
60833 if (inflight[tileID]) return;
60835 if (!cache[tileID]) {
60836 cache[tileID] = {};
60839 if (cache[tileID] && cache[tileID].metadata) {
60840 return callback(null, cache[tileID].metadata);
60843 inflight[tileID] = true;
60844 d3_json(url).then(function (result) {
60845 delete inflight[tileID];
60848 throw new Error('Unknown Error');
60852 start: localeDateString(result.resourceSets[0].resources[0].vintageStart),
60853 end: localeDateString(result.resourceSets[0].resources[0].vintageEnd)
60855 vintage.range = vintageRange(vintage);
60859 cache[tileID].metadata = metadata;
60860 if (callback) callback(null, metadata);
60861 })["catch"](function (err) {
60862 delete inflight[tileID];
60863 if (callback) callback(err.message);
60867 bing.terms_url = 'https://blog.openstreetmap.org/2010/11/30/microsoft-imagery-details';
60871 rendererBackgroundSource.Esri = function (data) {
60872 // in addition to using the tilemap at zoom level 20, overzoom real tiles - #4327 (deprecated technique, but it works)
60873 if (data.template.match(/blankTile/) === null) {
60874 data.template = data.template + '?blankTile=false';
60877 var esri = rendererBackgroundSource(data);
60881 var _prevCenter; // use a tilemap service to set maximum zoom for esri tiles dynamically
60882 // https://developers.arcgis.com/documentation/tiled-elevation-service/
60885 esri.fetchTilemap = function (center) {
60886 // skip if we have already fetched a tilemap within 5km
60887 if (_prevCenter && geoSphericalDistance(center, _prevCenter) < 5000) return;
60888 _prevCenter = center; // tiles are available globally to zoom level 19, afterward they may or may not be present
60890 var z = 20; // first generate a random url using the template
60892 var dummyUrl = esri.url([1, 2, 3]); // calculate url z/y/x from the lat/long of the center of the map
60894 var x = Math.floor((center[0] + 180) / 360 * Math.pow(2, z));
60895 var y = Math.floor((1 - Math.log(Math.tan(center[1] * Math.PI / 180) + 1 / Math.cos(center[1] * Math.PI / 180)) / Math.PI) / 2 * Math.pow(2, z)); // fetch an 8x8 grid to leverage cache
60897 var tilemapUrl = dummyUrl.replace(/tile\/[0-9]+\/[0-9]+\/[0-9]+\?blankTile=false/, 'tilemap') + '/' + z + '/' + y + '/' + x + '/8/8'; // make the request and introspect the response from the tilemap server
60899 d3_json(tilemapUrl).then(function (tilemap) {
60901 throw new Error('Unknown Error');
60904 var hasTiles = true;
60906 for (var i = 0; i < tilemap.data.length; i++) {
60907 // 0 means an individual tile in the grid doesn't exist
60908 if (!tilemap.data[i]) {
60912 } // if any tiles are missing at level 20 we restrict maxZoom to 19
60915 esri.zoomExtent[1] = hasTiles ? 22 : 19;
60916 })["catch"](function () {
60921 esri.getMetadata = function (center, tileCoord, callback) {
60922 var tileID = tileCoord.slice(0, 3).join('/');
60923 var zoom = Math.min(tileCoord[2], esri.zoomExtent[1]);
60924 var centerPoint = center[0] + ',' + center[1]; // long, lat (as it should be)
60926 var unknown = _t('info_panels.background.unknown');
60930 if (inflight[tileID]) return;
60933 case zoom >= 20 && esri.id === 'EsriWorldImageryClarity':
60950 metadataLayer = 99;
60953 var url; // build up query using the layer appropriate to the current zoom
60955 if (esri.id === 'EsriWorldImagery') {
60956 url = 'https://services.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/';
60957 } else if (esri.id === 'EsriWorldImageryClarity') {
60958 url = 'https://serviceslab.arcgisonline.com/arcgis/rest/services/Clarity_World_Imagery/MapServer/';
60961 url += metadataLayer + '/query?returnGeometry=false&geometry=' + centerPoint + '&inSR=4326&geometryType=esriGeometryPoint&outFields=*&f=json';
60963 if (!cache[tileID]) {
60964 cache[tileID] = {};
60967 if (cache[tileID] && cache[tileID].metadata) {
60968 return callback(null, cache[tileID].metadata);
60969 } // accurate metadata is only available >= 13
60972 if (metadataLayer === 99) {
60981 description: unknown,
60982 resolution: unknown,
60985 callback(null, metadata);
60987 inflight[tileID] = true;
60988 d3_json(url).then(function (result) {
60989 delete inflight[tileID];
60992 throw new Error('Unknown Error');
60993 } else if (result.features && result.features.length < 1) {
60994 throw new Error('No Results');
60995 } else if (result.error && result.error.message) {
60996 throw new Error(result.error.message);
60997 } // pass through the discrete capture date from metadata
61000 var captureDate = localeDateString(result.features[0].attributes.SRC_DATE2);
61002 start: captureDate,
61008 source: clean(result.features[0].attributes.NICE_NAME),
61009 description: clean(result.features[0].attributes.NICE_DESC),
61010 resolution: clean(+parseFloat(result.features[0].attributes.SRC_RES).toFixed(4)),
61011 accuracy: clean(+parseFloat(result.features[0].attributes.SRC_ACC).toFixed(4))
61012 }; // append units - meters
61014 if (isFinite(metadata.resolution)) {
61015 metadata.resolution += ' m';
61018 if (isFinite(metadata.accuracy)) {
61019 metadata.accuracy += ' m';
61022 cache[tileID].metadata = metadata;
61023 if (callback) callback(null, metadata);
61024 })["catch"](function (err) {
61025 delete inflight[tileID];
61026 if (callback) callback(err.message);
61030 function clean(val) {
61031 return String(val).trim() || unknown;
61038 rendererBackgroundSource.None = function () {
61039 var source = rendererBackgroundSource({
61044 source.name = function () {
61045 return _t('background.none');
61048 source.label = function () {
61049 return _t.html('background.none');
61052 source.imageryUsed = function () {
61056 source.area = function () {
61057 return -1; // sources in background pane are sorted by area
61063 rendererBackgroundSource.Custom = function (template) {
61064 var source = rendererBackgroundSource({
61069 source.name = function () {
61070 return _t('background.custom');
61073 source.label = function () {
61074 return _t.html('background.custom');
61077 source.imageryUsed = function () {
61078 // sanitize personal connection tokens - #6801
61079 var cleaned = source.template(); // from query string parameters
61081 if (cleaned.indexOf('?') !== -1) {
61082 var parts = cleaned.split('?', 2);
61083 var qs = utilStringQs(parts[1]);
61084 ['access_token', 'connectId', 'token'].forEach(function (param) {
61086 qs[param] = '{apikey}';
61089 cleaned = parts[0] + '?' + utilQsString(qs, true); // true = soft encode
61090 } // from wms/wmts api path parameters
61093 cleaned = cleaned.replace(/token\/(\w+)/, 'token/{apikey}');
61094 return 'Custom (' + cleaned + ' )';
61097 source.area = function () {
61098 return -2; // sources in background pane are sorted by area
61104 function rendererTileLayer(context) {
61105 var transformProp = utilPrefixCSSProperty('Transform');
61106 var tiler = utilTiler();
61107 var _tileSize = 256;
61119 function tileSizeAtZoom(d, z) {
61120 var EPSILON = 0.002; // close seams
61122 return _tileSize * Math.pow(2, z - d[2]) / _tileSize + EPSILON;
61125 function atZoom(t, distance) {
61126 var power = Math.pow(2, distance);
61127 return [Math.floor(t[0] * power), Math.floor(t[1] * power), t[2] + distance];
61130 function lookUp(d) {
61131 for (var up = -1; up > -d[2]; up--) {
61132 var tile = atZoom(d, up);
61134 if (_cache[_source.url(tile)] !== false) {
61140 function uniqueBy(a, n) {
61144 for (var i = 0; i < a.length; i++) {
61145 if (seen[a[i][n]] === undefined) {
61147 seen[a[i][n]] = true;
61154 function addSource(d) {
61155 d.push(_source.url(d));
61157 } // Update tiles based on current state of `projection`.
61160 function background(selection) {
61161 _zoom = geoScaleToZoom(_projection.scale(), _tileSize);
61165 pixelOffset = [_source.offset()[0] * Math.pow(2, _zoom), _source.offset()[1] * Math.pow(2, _zoom)];
61167 pixelOffset = [0, 0];
61170 var translate = [_projection.translate()[0] + pixelOffset[0], _projection.translate()[1] + pixelOffset[1]];
61171 tiler.scale(_projection.scale() * 2 * Math.PI).translate(translate);
61172 _tileOrigin = [_projection.scale() * Math.PI - translate[0], _projection.scale() * Math.PI - translate[1]];
61174 } // Derive the tiles onscreen, remove those offscreen and position them.
61175 // Important that this part not depend on `_projection` because it's
61176 // rentered when tiles load/error (see #644).
61179 function render(selection) {
61180 if (!_source) return;
61182 var showDebug = context.getDebug('tile') && !_source.overlay;
61184 if (_source.validZoom(_zoom)) {
61185 tiler.skipNullIsland(!!_source.overlay);
61186 tiler().forEach(function (d) {
61188 if (d[3] === '') return;
61189 if (typeof d[3] !== 'string') return; // Workaround for #2295
61193 if (_cache[d[3]] === false && lookUp(d)) {
61194 requests.push(addSource(lookUp(d)));
61197 requests = uniqueBy(requests, 3).filter(function (r) {
61198 // don't re-request tiles which have failed in the past
61199 return _cache[r[3]] !== false;
61203 function load(d3_event, d) {
61204 _cache[d[3]] = true;
61205 select(this).on('error', null).on('load', null).classed('tile-loaded', true);
61209 function error(d3_event, d) {
61210 _cache[d[3]] = false;
61211 select(this).on('error', null).on('load', null).remove();
61215 function imageTransform(d) {
61216 var ts = _tileSize * Math.pow(2, _zoom - d[2]);
61218 var scale = tileSizeAtZoom(d, _zoom);
61219 return 'translate(' + (d[0] * ts - _tileOrigin[0]) + 'px,' + (d[1] * ts - _tileOrigin[1]) + 'px) ' + 'scale(' + scale + ',' + scale + ')';
61222 function tileCenter(d) {
61223 var ts = _tileSize * Math.pow(2, _zoom - d[2]);
61225 return [d[0] * ts - _tileOrigin[0] + ts / 2, d[1] * ts - _tileOrigin[1] + ts / 2];
61228 function debugTransform(d) {
61229 var coord = tileCenter(d);
61230 return 'translate(' + coord[0] + 'px,' + coord[1] + 'px)';
61231 } // Pick a representative tile near the center of the viewport
61232 // (This is useful for sampling the imagery vintage)
61235 var dims = tiler.size();
61236 var mapCenter = [dims[0] / 2, dims[1] / 2];
61237 var minDist = Math.max(dims[0], dims[1]);
61239 requests.forEach(function (d) {
61240 var c = tileCenter(d);
61241 var dist = geoVecLength(c, mapCenter);
61243 if (dist < minDist) {
61248 var image = selection.selectAll('img').data(requests, function (d) {
61251 image.exit().style(transformProp, imageTransform).classed('tile-removing', true).classed('tile-center', false).each(function () {
61252 var tile = select(this);
61253 window.setTimeout(function () {
61254 if (tile.classed('tile-removing')) {
61259 image.enter().append('img').attr('class', 'tile').attr('draggable', 'false').style('width', _tileSize + 'px').style('height', _tileSize + 'px').attr('src', function (d) {
61261 }).on('error', error).on('load', load).merge(image).style(transformProp, imageTransform).classed('tile-debug', showDebug).classed('tile-removing', false).classed('tile-center', function (d) {
61262 return d === nearCenter;
61264 var debug = selection.selectAll('.tile-label-debug').data(showDebug ? requests : [], function (d) {
61267 debug.exit().remove();
61270 var debugEnter = debug.enter().append('div').attr('class', 'tile-label-debug');
61271 debugEnter.append('div').attr('class', 'tile-label-debug-coord');
61272 debugEnter.append('div').attr('class', 'tile-label-debug-vintage');
61273 debug = debug.merge(debugEnter);
61274 debug.style(transformProp, debugTransform);
61275 debug.selectAll('.tile-label-debug-coord').html(function (d) {
61276 return d[2] + ' / ' + d[0] + ' / ' + d[1];
61278 debug.selectAll('.tile-label-debug-vintage').each(function (d) {
61279 var span = select(this);
61280 var center = context.projection.invert(tileCenter(d));
61282 _source.getMetadata(center, d, function (err, result) {
61283 span.html(result && result.vintage && result.vintage.range || _t('info_panels.background.vintage') + ': ' + _t('info_panels.background.unknown'));
61289 background.projection = function (val) {
61290 if (!arguments.length) return _projection;
61295 background.dimensions = function (val) {
61296 if (!arguments.length) return tiler.size();
61301 background.source = function (val) {
61302 if (!arguments.length) return _source;
61304 _tileSize = _source.tileSize;
61306 tiler.tileSize(_source.tileSize).zoomExtent(_source.zoomExtent);
61313 var _imageryIndex = null;
61314 function rendererBackground(context) {
61315 var dispatch = dispatch$8('change');
61316 var detected = utilDetect();
61317 var baseLayer = rendererTileLayer(context).projection(context.projection);
61318 var _isValid = true;
61319 var _overlayLayers = [];
61320 var _brightness = 1;
61322 var _saturation = 1;
61323 var _sharpness = 1;
61325 function ensureImageryIndex() {
61326 return _mainFileFetcher.get('imagery').then(function (sources) {
61327 if (_imageryIndex) return _imageryIndex;
61331 }; // use which-polygon to support efficient index and querying for imagery
61333 var features = sources.map(function (source) {
61334 if (!source.polygon) return null; // workaround for editor-layer-index weirdness..
61335 // Add an extra array nest to each element in `source.polygon`
61336 // so the rings are not treated as a bunch of holes:
61337 // what we have: [ [[outer],[hole],[hole]] ]
61338 // what we want: [ [[outer]],[[outer]],[[outer]] ]
61340 var rings = source.polygon.map(function (ring) {
61349 type: 'MultiPolygon',
61353 _imageryIndex.features[source.id] = feature;
61355 }).filter(Boolean);
61356 _imageryIndex.query = whichPolygon_1({
61357 type: 'FeatureCollection',
61359 }); // Instantiate `rendererBackgroundSource` objects for each source
61361 _imageryIndex.backgrounds = sources.map(function (source) {
61362 if (source.type === 'bing') {
61363 return rendererBackgroundSource.Bing(source, dispatch);
61364 } else if (/^EsriWorldImagery/.test(source.id)) {
61365 return rendererBackgroundSource.Esri(source);
61367 return rendererBackgroundSource(source);
61371 _imageryIndex.backgrounds.unshift(rendererBackgroundSource.None()); // Add 'Custom'
61374 var template = corePreferences('background-custom-template') || '';
61375 var custom = rendererBackgroundSource.Custom(template);
61377 _imageryIndex.backgrounds.unshift(custom);
61379 return _imageryIndex;
61383 function background(selection) {
61384 var currSource = baseLayer.source(); // If we are displaying an Esri basemap at high zoom,
61385 // check its tilemap to see how high the zoom can go
61387 if (context.map().zoom() > 18) {
61388 if (currSource && /^EsriWorldImagery/.test(currSource.id)) {
61389 var center = context.map().center();
61390 currSource.fetchTilemap(center);
61392 } // Is the imagery valid here? - #4827
61395 var sources = background.sources(context.map().extent());
61396 var wasValid = _isValid;
61397 _isValid = !!sources.filter(function (d) {
61398 return d === currSource;
61401 if (wasValid !== _isValid) {
61402 // change in valid status
61403 background.updateImagery();
61406 var baseFilter = '';
61408 if (detected.cssfilters) {
61409 if (_brightness !== 1) {
61410 baseFilter += " brightness(".concat(_brightness, ")");
61413 if (_contrast !== 1) {
61414 baseFilter += " contrast(".concat(_contrast, ")");
61417 if (_saturation !== 1) {
61418 baseFilter += " saturate(".concat(_saturation, ")");
61421 if (_sharpness < 1) {
61423 var blur = d3_interpolateNumber(0.5, 5)(1 - _sharpness);
61424 baseFilter += " blur(".concat(blur, "px)");
61428 var base = selection.selectAll('.layer-background').data([0]);
61429 base = base.enter().insert('div', '.layer-data').attr('class', 'layer layer-background').merge(base);
61431 if (detected.cssfilters) {
61432 base.style('filter', baseFilter || null);
61434 base.style('opacity', _brightness);
61437 var imagery = base.selectAll('.layer-imagery').data([0]);
61438 imagery.enter().append('div').attr('class', 'layer layer-imagery').merge(imagery).call(baseLayer);
61439 var maskFilter = '';
61440 var mixBlendMode = '';
61442 if (detected.cssfilters && _sharpness > 1) {
61443 // apply unsharp mask
61444 mixBlendMode = 'overlay';
61445 maskFilter = 'saturate(0) blur(3px) invert(1)';
61446 var contrast = _sharpness - 1;
61447 maskFilter += " contrast(".concat(contrast, ")");
61448 var brightness = d3_interpolateNumber(1, 0.85)(_sharpness - 1);
61449 maskFilter += " brightness(".concat(brightness, ")");
61452 var mask = base.selectAll('.layer-unsharp-mask').data(detected.cssfilters && _sharpness > 1 ? [0] : []);
61453 mask.exit().remove();
61454 mask.enter().append('div').attr('class', 'layer layer-mask layer-unsharp-mask').merge(mask).call(baseLayer).style('filter', maskFilter || null).style('mix-blend-mode', mixBlendMode || null);
61455 var overlays = selection.selectAll('.layer-overlay').data(_overlayLayers, function (d) {
61456 return d.source().name();
61458 overlays.exit().remove();
61459 overlays.enter().insert('div', '.layer-data').attr('class', 'layer layer-overlay').merge(overlays).each(function (layer, i, nodes) {
61460 return select(nodes[i]).call(layer);
61464 background.updateImagery = function () {
61465 var currSource = baseLayer.source();
61466 if (context.inIntro() || !currSource) return;
61468 var o = _overlayLayers.filter(function (d) {
61469 return !d.source().isLocatorOverlay() && !d.source().isHidden();
61470 }).map(function (d) {
61471 return d.source().id;
61474 var meters = geoOffsetToMeters(currSource.offset());
61475 var EPSILON = 0.01;
61476 var x = +meters[0].toFixed(2);
61477 var y = +meters[1].toFixed(2);
61478 var hash = utilStringQs(window.location.hash);
61479 var id = currSource.id;
61481 if (id === 'custom') {
61482 id = "custom:".concat(currSource.template());
61486 hash.background = id;
61488 delete hash.background;
61494 delete hash.overlays;
61497 if (Math.abs(x) > EPSILON || Math.abs(y) > EPSILON) {
61498 hash.offset = "".concat(x, ",").concat(y);
61500 delete hash.offset;
61503 if (!window.mocha) {
61504 window.location.replace('#' + utilQsString(hash, true));
61507 var imageryUsed = [];
61508 var photoOverlaysUsed = [];
61509 var currUsed = currSource.imageryUsed();
61511 if (currUsed && _isValid) {
61512 imageryUsed.push(currUsed);
61515 _overlayLayers.filter(function (d) {
61516 return !d.source().isLocatorOverlay() && !d.source().isHidden();
61517 }).forEach(function (d) {
61518 return imageryUsed.push(d.source().imageryUsed());
61521 var dataLayer = context.layers().layer('data');
61523 if (dataLayer && dataLayer.enabled() && dataLayer.hasData()) {
61524 imageryUsed.push(dataLayer.getSrc());
61527 var photoOverlayLayers = {
61528 streetside: 'Bing Streetside',
61529 mapillary: 'Mapillary Images',
61530 'mapillary-map-features': 'Mapillary Map Features',
61531 'mapillary-signs': 'Mapillary Signs',
61532 openstreetcam: 'OpenStreetCam Images'
61535 for (var layerID in photoOverlayLayers) {
61536 var layer = context.layers().layer(layerID);
61538 if (layer && layer.enabled()) {
61539 photoOverlaysUsed.push(layerID);
61540 imageryUsed.push(photoOverlayLayers[layerID]);
61544 context.history().imageryUsed(imageryUsed);
61545 context.history().photoOverlaysUsed(photoOverlaysUsed);
61548 var _checkedBlocklists;
61550 background.sources = function (extent, zoom, includeCurrent) {
61551 if (!_imageryIndex) return []; // called before init()?
61554 (_imageryIndex.query.bbox(extent.rectangle(), true) || []).forEach(function (d) {
61555 return visible[d.id] = true;
61557 var currSource = baseLayer.source();
61558 var osm = context.connection();
61559 var blocklists = osm && osm.imageryBlocklists();
61561 if (blocklists && blocklists !== _checkedBlocklists) {
61562 _imageryIndex.backgrounds.forEach(function (source) {
61563 source.isBlocked = blocklists.some(function (blocklist) {
61564 return blocklist.test(source.template());
61568 _checkedBlocklists = blocklists;
61571 return _imageryIndex.backgrounds.filter(function (source) {
61572 if (includeCurrent && currSource === source) return true; // optionally always include the current imagery
61574 if (source.isBlocked) return false; // even bundled sources may be blocked - #7905
61576 if (!source.polygon) return true; // always include imagery with worldwide coverage
61578 if (zoom && zoom < 6) return false; // optionally exclude local imagery at low zooms
61580 return visible[source.id]; // include imagery visible in given extent
61584 background.dimensions = function (val) {
61586 baseLayer.dimensions(val);
61588 _overlayLayers.forEach(function (layer) {
61589 return layer.dimensions(val);
61593 background.baseLayerSource = function (d) {
61594 if (!arguments.length) return baseLayer.source(); // test source against OSM imagery blocklists..
61596 var osm = context.connection();
61597 if (!osm) return background;
61598 var blocklists = osm.imageryBlocklists();
61599 var template = d.template();
61604 for (var i = 0; i < blocklists.length; i++) {
61605 regex = blocklists[i];
61606 fail = regex.test(template);
61609 } // ensure at least one test was run.
61613 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
61614 fail = regex.test(template);
61617 baseLayer.source(!fail ? d : background.findSource('none'));
61618 dispatch.call('change');
61619 background.updateImagery();
61623 background.findSource = function (id) {
61624 if (!id || !_imageryIndex) return null; // called before init()?
61626 return _imageryIndex.backgrounds.find(function (d) {
61627 return d.id && d.id === id;
61631 background.bing = function () {
61632 background.baseLayerSource(background.findSource('Bing'));
61635 background.showsLayer = function (d) {
61636 var currSource = baseLayer.source();
61637 if (!d || !currSource) return false;
61638 return d.id === currSource.id || _overlayLayers.some(function (layer) {
61639 return d.id === layer.source().id;
61643 background.overlayLayerSources = function () {
61644 return _overlayLayers.map(function (layer) {
61645 return layer.source();
61649 background.toggleOverlayLayer = function (d) {
61652 for (var i = 0; i < _overlayLayers.length; i++) {
61653 layer = _overlayLayers[i];
61655 if (layer.source() === d) {
61656 _overlayLayers.splice(i, 1);
61658 dispatch.call('change');
61659 background.updateImagery();
61664 layer = rendererTileLayer(context).source(d).projection(context.projection).dimensions(baseLayer.dimensions());
61666 _overlayLayers.push(layer);
61668 dispatch.call('change');
61669 background.updateImagery();
61672 background.nudge = function (d, zoom) {
61673 var currSource = baseLayer.source();
61676 currSource.nudge(d, zoom);
61677 dispatch.call('change');
61678 background.updateImagery();
61684 background.offset = function (d) {
61685 var currSource = baseLayer.source();
61687 if (!arguments.length) {
61688 return currSource && currSource.offset() || [0, 0];
61692 currSource.offset(d);
61693 dispatch.call('change');
61694 background.updateImagery();
61700 background.brightness = function (d) {
61701 if (!arguments.length) return _brightness;
61703 if (context.mode()) dispatch.call('change');
61707 background.contrast = function (d) {
61708 if (!arguments.length) return _contrast;
61710 if (context.mode()) dispatch.call('change');
61714 background.saturation = function (d) {
61715 if (!arguments.length) return _saturation;
61717 if (context.mode()) dispatch.call('change');
61721 background.sharpness = function (d) {
61722 if (!arguments.length) return _sharpness;
61724 if (context.mode()) dispatch.call('change');
61730 background.ensureLoaded = function () {
61731 if (_loadPromise) return _loadPromise;
61733 function parseMapParams(qmap) {
61734 if (!qmap) return false;
61735 var params = qmap.split('/').map(Number);
61736 if (params.length < 3 || params.some(isNaN)) return false;
61737 return geoExtent([params[2], params[1]]); // lon,lat
61740 var hash = utilStringQs(window.location.hash);
61741 var requested = hash.background || hash.layer;
61742 var extent = parseMapParams(hash.map);
61743 return _loadPromise = ensureImageryIndex().then(function (imageryIndex) {
61744 var first = imageryIndex.backgrounds.length && imageryIndex.backgrounds[0];
61747 if (!requested && extent) {
61748 best = background.sources(extent).find(function (s) {
61751 } // Decide which background layer to display
61754 if (requested && requested.indexOf('custom:') === 0) {
61755 var template = requested.replace(/^custom:/, '');
61756 var custom = background.findSource('custom');
61757 background.baseLayerSource(custom.template(template));
61758 corePreferences('background-custom-template', template);
61760 background.baseLayerSource(background.findSource(requested) || best || background.findSource(corePreferences('background-last-used')) || background.findSource('Bing') || first || background.findSource('none'));
61763 var locator = imageryIndex.backgrounds.find(function (d) {
61764 return d.overlay && d["default"];
61768 background.toggleOverlayLayer(locator);
61771 var overlays = (hash.overlays || '').split(',');
61772 overlays.forEach(function (overlay) {
61773 overlay = background.findSource(overlay);
61776 background.toggleOverlayLayer(overlay);
61781 var gpx = context.layers().layer('data');
61784 gpx.url(hash.gpx, '.gpx');
61789 var offset = hash.offset.replace(/;/g, ',').split(',').map(function (n) {
61790 return !isNaN(n) && n;
61793 if (offset.length === 2) {
61794 background.offset(geoMetersToOffset(offset));
61797 })["catch"](function () {
61802 return utilRebind(background, dispatch, 'on');
61805 function rendererFeatures(context) {
61806 var dispatch = dispatch$8('change', 'redraw');
61807 var features = utilRebind({}, dispatch, 'on');
61809 var _deferred = new Set();
61811 var traffic_roads = {
61813 'motorway_link': true,
61815 'trunk_link': true,
61817 'primary_link': true,
61819 'secondary_link': true,
61821 'tertiary_link': true,
61822 'residential': true,
61823 'unclassified': true,
61824 'living_street': true
61826 var service_roads = {
61839 var past_futures = {
61841 'construction': true,
61843 'dismantled': true,
61846 'demolished': true,
61847 'obliterated': true
61849 var _cullFactor = 1;
61855 var _forceVisible = {};
61857 function update() {
61858 if (!window.mocha) {
61859 var hash = utilStringQs(window.location.hash);
61860 var disabled = features.disabled();
61862 if (disabled.length) {
61863 hash.disable_features = disabled.join(',');
61865 delete hash.disable_features;
61868 window.location.replace('#' + utilQsString(hash, true));
61869 corePreferences('disabled-features', disabled.join(','));
61872 _hidden = features.hidden();
61873 dispatch.call('change');
61874 dispatch.call('redraw');
61877 function defineRule(k, filter, max) {
61878 var isEnabled = true;
61884 enabled: isEnabled,
61885 // whether the user wants it enabled..
61887 currentMax: max || Infinity,
61888 defaultMax: max || Infinity,
61889 enable: function enable() {
61890 this.enabled = true;
61891 this.currentMax = this.defaultMax;
61893 disable: function disable() {
61894 this.enabled = false;
61895 this.currentMax = 0;
61897 hidden: function hidden() {
61898 return this.count === 0 && !this.enabled || this.count > this.currentMax * _cullFactor;
61900 autoHidden: function autoHidden() {
61901 return this.hidden() && this.currentMax > 0;
61906 defineRule('points', function isPoint(tags, geometry) {
61907 return geometry === 'point';
61909 defineRule('traffic_roads', function isTrafficRoad(tags) {
61910 return traffic_roads[tags.highway];
61912 defineRule('service_roads', function isServiceRoad(tags) {
61913 return service_roads[tags.highway];
61915 defineRule('paths', function isPath(tags) {
61916 return paths[tags.highway];
61918 defineRule('buildings', function isBuilding(tags) {
61919 return !!tags.building && tags.building !== 'no' || tags.parking === 'multi-storey' || tags.parking === 'sheds' || tags.parking === 'carports' || tags.parking === 'garage_boxes';
61921 defineRule('building_parts', function isBuildingPart(tags) {
61922 return tags['building:part'];
61924 defineRule('indoor', function isIndoor(tags) {
61925 return tags.indoor;
61927 defineRule('landuse', function isLanduse(tags, geometry) {
61928 return geometry === 'area' && !_rules.buildings.filter(tags) && !_rules.building_parts.filter(tags) && !_rules.indoor.filter(tags) && !_rules.water.filter(tags) && !_rules.pistes.filter(tags);
61930 defineRule('boundaries', function isBoundary(tags) {
61931 return !!tags.boundary && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway] || tags.waterway || tags.railway || tags.landuse || tags.natural || tags.building || tags.power);
61933 defineRule('water', function isWater(tags) {
61934 return !!tags.waterway || tags.natural === 'water' || tags.natural === 'coastline' || tags.natural === 'bay' || tags.landuse === 'pond' || tags.landuse === 'basin' || tags.landuse === 'reservoir' || tags.landuse === 'salt_pond';
61936 defineRule('rail', function isRail(tags) {
61937 return (!!tags.railway || tags.landuse === 'railway') && !(traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]);
61939 defineRule('pistes', function isPiste(tags) {
61940 return tags['piste:type'];
61942 defineRule('aerialways', function isPiste(tags) {
61943 return tags.aerialway && tags.aerialway !== 'yes' && tags.aerialway !== 'station';
61945 defineRule('power', function isPower(tags) {
61946 return !!tags.power;
61947 }); // contains a past/future tag, but not in active use as a road/path/cycleway/etc..
61949 defineRule('past_future', function isPastFuture(tags) {
61950 if (traffic_roads[tags.highway] || service_roads[tags.highway] || paths[tags.highway]) {
61954 var strings = Object.keys(tags);
61956 for (var i = 0; i < strings.length; i++) {
61957 var s = strings[i];
61959 if (past_futures[s] || past_futures[tags[s]]) {
61965 }); // Lines or areas that don't match another feature filter.
61966 // IMPORTANT: The 'others' feature must be the last one defined,
61967 // so that code in getMatches can skip this test if `hasMatch = true`
61969 defineRule('others', function isOther(tags, geometry) {
61970 return geometry === 'line' || geometry === 'area';
61973 features.features = function () {
61977 features.keys = function () {
61981 features.enabled = function (k) {
61982 if (!arguments.length) {
61983 return _keys.filter(function (k) {
61984 return _rules[k].enabled;
61988 return _rules[k] && _rules[k].enabled;
61991 features.disabled = function (k) {
61992 if (!arguments.length) {
61993 return _keys.filter(function (k) {
61994 return !_rules[k].enabled;
61998 return _rules[k] && !_rules[k].enabled;
62001 features.hidden = function (k) {
62002 if (!arguments.length) {
62003 return _keys.filter(function (k) {
62004 return _rules[k].hidden();
62008 return _rules[k] && _rules[k].hidden();
62011 features.autoHidden = function (k) {
62012 if (!arguments.length) {
62013 return _keys.filter(function (k) {
62014 return _rules[k].autoHidden();
62018 return _rules[k] && _rules[k].autoHidden();
62021 features.enable = function (k) {
62022 if (_rules[k] && !_rules[k].enabled) {
62023 _rules[k].enable();
62029 features.enableAll = function () {
62030 var didEnable = false;
62032 for (var k in _rules) {
62033 if (!_rules[k].enabled) {
62036 _rules[k].enable();
62040 if (didEnable) update();
62043 features.disable = function (k) {
62044 if (_rules[k] && _rules[k].enabled) {
62045 _rules[k].disable();
62051 features.disableAll = function () {
62052 var didDisable = false;
62054 for (var k in _rules) {
62055 if (_rules[k].enabled) {
62058 _rules[k].disable();
62062 if (didDisable) update();
62065 features.toggle = function (k) {
62068 return f.enabled ? f.disable() : f.enable();
62075 features.resetStats = function () {
62076 for (var i = 0; i < _keys.length; i++) {
62077 _rules[_keys[i]].count = 0;
62080 dispatch.call('change');
62083 features.gatherStats = function (d, resolver, dimensions) {
62084 var needsRedraw = false;
62085 var types = utilArrayGroupBy(d, 'type');
62086 var entities = [].concat(types.relation || [], types.way || [], types.node || []);
62087 var currHidden, geometry, matches, i, j;
62089 for (i = 0; i < _keys.length; i++) {
62090 _rules[_keys[i]].count = 0;
62091 } // adjust the threshold for point/building culling based on viewport size..
62092 // a _cullFactor of 1 corresponds to a 1000x1000px viewport..
62095 _cullFactor = dimensions[0] * dimensions[1] / 1000000;
62097 for (i = 0; i < entities.length; i++) {
62098 geometry = entities[i].geometry(resolver);
62099 matches = Object.keys(features.getMatches(entities[i], resolver, geometry));
62101 for (j = 0; j < matches.length; j++) {
62102 _rules[matches[j]].count++;
62106 currHidden = features.hidden();
62108 if (currHidden !== _hidden) {
62109 _hidden = currHidden;
62110 needsRedraw = true;
62111 dispatch.call('change');
62114 return needsRedraw;
62117 features.stats = function () {
62118 for (var i = 0; i < _keys.length; i++) {
62119 _stats[_keys[i]] = _rules[_keys[i]].count;
62125 features.clear = function (d) {
62126 for (var i = 0; i < d.length; i++) {
62127 features.clearEntity(d[i]);
62131 features.clearEntity = function (entity) {
62132 delete _cache[osmEntity.key(entity)];
62135 features.reset = function () {
62136 Array.from(_deferred).forEach(function (handle) {
62137 window.cancelIdleCallback(handle);
62139 _deferred["delete"](handle);
62142 }; // only certain relations are worth checking
62145 function relationShouldBeChecked(relation) {
62146 // multipolygon features have `area` geometry and aren't checked here
62147 return relation.tags.type === 'boundary';
62150 features.getMatches = function (entity, resolver, geometry) {
62151 if (geometry === 'vertex' || geometry === 'relation' && !relationShouldBeChecked(entity)) return {};
62152 var ent = osmEntity.key(entity);
62154 if (!_cache[ent]) {
62158 if (!_cache[ent].matches) {
62160 var hasMatch = false;
62162 for (var i = 0; i < _keys.length; i++) {
62163 if (_keys[i] === 'others') {
62164 if (hasMatch) continue; // If an entity...
62165 // 1. is a way that hasn't matched other 'interesting' feature rules,
62167 if (entity.type === 'way') {
62168 var parents = features.getParents(entity, resolver, geometry); // 2a. belongs only to a single multipolygon relation
62170 if (parents.length === 1 && parents[0].isMultipolygon() || // 2b. or belongs only to boundary relations
62171 parents.length > 0 && parents.every(function (parent) {
62172 return parent.tags.type === 'boundary';
62174 // ...then match whatever feature rules the parent relation has matched.
62175 // see #2548, #2887
62178 // For this to work, getMatches must be called on relations before ways.
62180 var pkey = osmEntity.key(parents[0]);
62182 if (_cache[pkey] && _cache[pkey].matches) {
62183 matches = Object.assign({}, _cache[pkey].matches); // shallow copy
62191 if (_rules[_keys[i]].filter(entity.tags, geometry)) {
62192 matches[_keys[i]] = hasMatch = true;
62196 _cache[ent].matches = matches;
62199 return _cache[ent].matches;
62202 features.getParents = function (entity, resolver, geometry) {
62203 if (geometry === 'point') return [];
62204 var ent = osmEntity.key(entity);
62206 if (!_cache[ent]) {
62210 if (!_cache[ent].parents) {
62213 if (geometry === 'vertex') {
62214 parents = resolver.parentWays(entity);
62216 // 'line', 'area', 'relation'
62217 parents = resolver.parentRelations(entity);
62220 _cache[ent].parents = parents;
62223 return _cache[ent].parents;
62226 features.isHiddenPreset = function (preset, geometry) {
62227 if (!_hidden.length) return false;
62228 if (!preset.tags) return false;
62229 var test = preset.setTags({}, geometry);
62231 for (var key in _rules) {
62232 if (_rules[key].filter(test, geometry)) {
62233 if (_hidden.indexOf(key) !== -1) {
62244 features.isHiddenFeature = function (entity, resolver, geometry) {
62245 if (!_hidden.length) return false;
62246 if (!entity.version) return false;
62247 if (_forceVisible[entity.id]) return false;
62248 var matches = Object.keys(features.getMatches(entity, resolver, geometry));
62249 return matches.length && matches.every(function (k) {
62250 return features.hidden(k);
62254 features.isHiddenChild = function (entity, resolver, geometry) {
62255 if (!_hidden.length) return false;
62256 if (!entity.version || geometry === 'point') return false;
62257 if (_forceVisible[entity.id]) return false;
62258 var parents = features.getParents(entity, resolver, geometry);
62259 if (!parents.length) return false;
62261 for (var i = 0; i < parents.length; i++) {
62262 if (!features.isHidden(parents[i], resolver, parents[i].geometry(resolver))) {
62270 features.hasHiddenConnections = function (entity, resolver) {
62271 if (!_hidden.length) return false;
62272 var childNodes, connections;
62274 if (entity.type === 'midpoint') {
62275 childNodes = [resolver.entity(entity.edge[0]), resolver.entity(entity.edge[1])];
62278 childNodes = entity.nodes ? resolver.childNodes(entity) : [];
62279 connections = features.getParents(entity, resolver, entity.geometry(resolver));
62280 } // gather ways connected to child nodes..
62283 connections = childNodes.reduce(function (result, e) {
62284 return resolver.isShared(e) ? utilArrayUnion(result, resolver.parentWays(e)) : result;
62286 return connections.some(function (e) {
62287 return features.isHidden(e, resolver, e.geometry(resolver));
62291 features.isHidden = function (entity, resolver, geometry) {
62292 if (!_hidden.length) return false;
62293 if (!entity.version) return false;
62294 var fn = geometry === 'vertex' ? features.isHiddenChild : features.isHiddenFeature;
62295 return fn(entity, resolver, geometry);
62298 features.filter = function (d, resolver) {
62299 if (!_hidden.length) return d;
62302 for (var i = 0; i < d.length; i++) {
62305 if (!features.isHidden(entity, resolver, entity.geometry(resolver))) {
62306 result.push(entity);
62313 features.forceVisible = function (entityIDs) {
62314 if (!arguments.length) return Object.keys(_forceVisible);
62315 _forceVisible = {};
62317 for (var i = 0; i < entityIDs.length; i++) {
62318 _forceVisible[entityIDs[i]] = true;
62319 var entity = context.hasEntity(entityIDs[i]);
62321 if (entity && entity.type === 'relation') {
62322 // also show relation members (one level deep)
62323 for (var j in entity.members) {
62324 _forceVisible[entity.members[j].id] = true;
62332 features.init = function () {
62333 var storage = corePreferences('disabled-features');
62336 var storageDisabled = storage.replace(/;/g, ',').split(',');
62337 storageDisabled.forEach(features.disable);
62340 var hash = utilStringQs(window.location.hash);
62342 if (hash.disable_features) {
62343 var hashDisabled = hash.disable_features.replace(/;/g, ',').split(',');
62344 hashDisabled.forEach(features.disable);
62346 }; // warm up the feature matching cache upon merging fetched data
62349 context.history().on('merge.features', function (newEntities) {
62350 if (!newEntities) return;
62351 var handle = window.requestIdleCallback(function () {
62352 var graph = context.graph();
62353 var types = utilArrayGroupBy(newEntities, 'type'); // ensure that getMatches is called on relations before ways
62355 var entities = [].concat(types.relation || [], types.way || [], types.node || []);
62357 for (var i = 0; i < entities.length; i++) {
62358 var geometry = entities[i].geometry(graph);
62359 features.getMatches(entities[i], graph, geometry);
62363 _deferred.add(handle);
62368 /** Error message constants. */
62370 var FUNC_ERROR_TEXT = 'Expected a function';
62372 * Creates a throttled function that only invokes `func` at most once per
62373 * every `wait` milliseconds. The throttled function comes with a `cancel`
62374 * method to cancel delayed `func` invocations and a `flush` method to
62375 * immediately invoke them. Provide `options` to indicate whether `func`
62376 * should be invoked on the leading and/or trailing edge of the `wait`
62377 * timeout. The `func` is invoked with the last arguments provided to the
62378 * throttled function. Subsequent calls to the throttled function return the
62379 * result of the last `func` invocation.
62381 * **Note:** If `leading` and `trailing` options are `true`, `func` is
62382 * invoked on the trailing edge of the timeout only if the throttled function
62383 * is invoked more than once during the `wait` timeout.
62385 * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred
62386 * until to the next tick, similar to `setTimeout` with a timeout of `0`.
62388 * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
62389 * for details over the differences between `_.throttle` and `_.debounce`.
62394 * @category Function
62395 * @param {Function} func The function to throttle.
62396 * @param {number} [wait=0] The number of milliseconds to throttle invocations to.
62397 * @param {Object} [options={}] The options object.
62398 * @param {boolean} [options.leading=true]
62399 * Specify invoking on the leading edge of the timeout.
62400 * @param {boolean} [options.trailing=true]
62401 * Specify invoking on the trailing edge of the timeout.
62402 * @returns {Function} Returns the new throttled function.
62405 * // Avoid excessively updating the position while scrolling.
62406 * jQuery(window).on('scroll', _.throttle(updatePosition, 100));
62408 * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
62409 * var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
62410 * jQuery(element).on('click', throttled);
62412 * // Cancel the trailing throttled invocation.
62413 * jQuery(window).on('popstate', throttled.cancel);
62416 function throttle(func, wait, options) {
62417 var leading = true,
62420 if (typeof func != 'function') {
62421 throw new TypeError(FUNC_ERROR_TEXT);
62424 if (isObject$2(options)) {
62425 leading = 'leading' in options ? !!options.leading : leading;
62426 trailing = 'trailing' in options ? !!options.trailing : trailing;
62429 return debounce(func, wait, {
62430 'leading': leading,
62432 'trailing': trailing
62437 // - the activeID - nope
62438 // - 1 away (adjacent) to the activeID - yes (vertices will be merged)
62439 // - 2 away from the activeID - nope (would create a self intersecting segment)
62440 // - all others on a linear way - yes
62441 // - all others on a closed way - nope (would create a self intersecting polygon)
62444 // 0 = active vertex - no touch/connect
62445 // 1 = passive vertex - yes touch/connect
62446 // 2 = adjacent vertex - yes but pay attention segmenting a line here
62449 function svgPassiveVertex(node, graph, activeID) {
62450 if (!activeID) return 1;
62451 if (activeID === node.id) return 0;
62452 var parents = graph.parentWays(node);
62453 var i, j, nodes, isClosed, ix1, ix2, ix3, ix4, max;
62455 for (i = 0; i < parents.length; i++) {
62456 nodes = parents[i].nodes;
62457 isClosed = parents[i].isClosed();
62459 for (j = 0; j < nodes.length; j++) {
62460 // find this vertex, look nearby
62461 if (nodes[j] === node.id) {
62468 // wraparound if needed
62469 max = nodes.length - 1;
62470 if (ix1 < 0) ix1 = max + ix1;
62471 if (ix2 < 0) ix2 = max + ix2;
62472 if (ix3 > max) ix3 = ix3 - max;
62473 if (ix4 > max) ix4 = ix4 - max;
62476 if (nodes[ix1] === activeID) return 0; // no - prevent self intersect
62477 else if (nodes[ix2] === activeID) return 2; // ok - adjacent
62478 else if (nodes[ix3] === activeID) return 2; // ok - adjacent
62479 else if (nodes[ix4] === activeID) return 0; // no - prevent self intersect
62480 else if (isClosed && nodes.indexOf(activeID) !== -1) return 0; // no - prevent self intersect
62487 function svgMarkerSegments(projection, graph, dt, shouldReverse, bothDirections) {
62488 return function (entity) {
62492 var clip = d3_geoIdentity().clipExtent(projection.clipExtent()).stream;
62493 var coordinates = graph.childNodes(entity).map(function (n) {
62498 if (shouldReverse(entity)) {
62499 coordinates.reverse();
62503 type: 'LineString',
62504 coordinates: coordinates
62505 }, projection.stream(clip({
62506 lineStart: function lineStart() {},
62507 lineEnd: function lineEnd() {
62510 point: function point(x, y) {
62514 var span = geoVecLength(a, b) - offset;
62517 var heading = geoVecAngle(a, b);
62518 var dx = dt * Math.cos(heading);
62519 var dy = dt * Math.sin(heading);
62520 var p = [a[0] + offset * Math.cos(heading), a[1] + offset * Math.sin(heading)]; // gather coordinates
62522 var coord = [a, p];
62524 for (span -= dt; span >= 0; span -= dt) {
62525 p = geoVecAdd(p, [dx, dy]);
62529 coord.push(b); // generate svg paths
62534 for (j = 0; j < coord.length; j++) {
62535 segment += (j === 0 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
62544 if (bothDirections(entity)) {
62547 for (j = coord.length - 1; j >= 0; j--) {
62548 segment += (j === coord.length - 1 ? 'M' : 'L') + coord[j][0] + ',' + coord[j][1];
62568 function svgPath(projection, graph, isArea) {
62569 // Explanation of magic numbers:
62570 // "padding" here allows space for strokes to extend beyond the viewport,
62571 // so that the stroke isn't drawn along the edge of the viewport when
62572 // the shape is clipped.
62574 // When drawing lines, pad viewport by 5px.
62575 // When drawing areas, pad viewport by 65px in each direction to allow
62576 // for 60px area fill stroke (see ".fill-partial path.fill" css rule)
62578 var padding = isArea ? 65 : 5;
62579 var viewport = projection.clipExtent();
62580 var paddedExtent = [[viewport[0][0] - padding, viewport[0][1] - padding], [viewport[1][0] + padding, viewport[1][1] + padding]];
62581 var clip = d3_geoIdentity().clipExtent(paddedExtent).stream;
62582 var project = projection.stream;
62583 var path = d3_geoPath().projection({
62584 stream: function stream(output) {
62585 return project(clip(output));
62589 var svgpath = function svgpath(entity) {
62590 if (entity.id in cache) {
62591 return cache[entity.id];
62593 return cache[entity.id] = path(entity.asGeoJSON(graph));
62597 svgpath.geojson = function (d) {
62598 if (d.__featurehash__ !== undefined) {
62599 if (d.__featurehash__ in cache) {
62600 return cache[d.__featurehash__];
62602 return cache[d.__featurehash__] = path(d);
62611 function svgPointTransform(projection) {
62612 var svgpoint = function svgpoint(entity) {
62613 // http://jsperf.com/short-array-join
62614 var pt = projection(entity.loc);
62615 return 'translate(' + pt[0] + ',' + pt[1] + ')';
62618 svgpoint.geojson = function (d) {
62619 return svgpoint(d.properties.entity);
62624 function svgRelationMemberTags(graph) {
62625 return function (entity) {
62626 var tags = entity.tags;
62627 var shouldCopyMultipolygonTags = !entity.hasInterestingTags();
62628 graph.parentRelations(entity).forEach(function (relation) {
62629 var type = relation.tags.type;
62631 if (type === 'multipolygon' && shouldCopyMultipolygonTags || type === 'boundary') {
62632 tags = Object.assign({}, relation.tags, tags);
62638 function svgSegmentWay(way, graph, activeID) {
62639 // When there is no activeID, we can memoize this expensive computation
62640 if (activeID === undefined) {
62641 return graph["transient"](way, 'waySegments', getWaySegments);
62643 return getWaySegments();
62646 function getWaySegments() {
62647 var isActiveWay = way.nodes.indexOf(activeID) !== -1;
62656 for (var i = 0; i < way.nodes.length; i++) {
62657 node = graph.entity(way.nodes[i]);
62658 type = svgPassiveVertex(node, graph, activeID);
62664 if (start.type !== undefined) {
62665 if (start.node.id === activeID || end.node.id === activeID) ; else if (isActiveWay && (start.type === 2 || end.type === 2)) {
62666 // one adjacent vertex
62667 pushActive(start, end, i);
62668 } else if (start.type === 0 && end.type === 0) {
62669 // both active vertices
62670 pushActive(start, end, i);
62672 pushPassive(start, end, i);
62681 function pushActive(start, end, index) {
62682 features.active.push({
62684 id: way.id + '-' + index + '-nope',
62689 nodes: [start.node, end.node],
62693 type: 'LineString',
62694 coordinates: [start.node.loc, end.node.loc]
62699 function pushPassive(start, end, index) {
62700 features.passive.push({
62702 id: way.id + '-' + index,
62706 nodes: [start.node, end.node],
62710 type: 'LineString',
62711 coordinates: [start.node.loc, end.node.loc]
62718 function svgTagClasses() {
62719 var primaries = ['building', 'highway', 'railway', 'waterway', 'aeroway', 'aerialway', 'piste:type', 'boundary', 'power', 'amenity', 'natural', 'landuse', 'leisure', 'military', 'place', 'man_made', 'route', 'attraction', 'building:part', 'indoor'];
62720 var statuses = [// nonexistent, might be built
62721 'proposed', 'planned', // under maintentance or between groundbreaking and opening
62722 'construction', // existent but not functional
62723 'disused', // dilapidated to nonexistent
62724 'abandoned', // nonexistent, still may appear in imagery
62725 'dismantled', 'razed', 'demolished', 'obliterated', // existent occasionally, e.g. stormwater drainage basin
62727 var secondaries = ['oneway', 'bridge', 'tunnel', 'embankment', 'cutting', 'barrier', 'surface', 'tracktype', 'footway', 'crossing', 'service', 'sport', 'public_transport', 'location', 'parking', 'golf', 'type', 'leisure', 'man_made', 'indoor'];
62729 var _tags = function _tags(entity) {
62730 return entity.tags;
62733 var tagClasses = function tagClasses(selection) {
62734 selection.each(function tagClassesEach(entity) {
62735 var value = this.className;
62737 if (value.baseVal !== undefined) {
62738 value = value.baseVal;
62741 var t = _tags(entity);
62743 var computed = tagClasses.getClassesString(t, value);
62745 if (computed !== value) {
62746 select(this).attr('class', computed);
62751 tagClasses.getClassesString = function (t, value) {
62752 var primary, status;
62753 var i, j, k, v; // in some situations we want to render perimeter strokes a certain way
62755 var overrideGeometry;
62757 if (/\bstroke\b/.test(value)) {
62758 if (!!t.barrier && t.barrier !== 'no') {
62759 overrideGeometry = 'line';
62761 } // preserve base classes (nothing with `tag-`)
62764 var classes = value.trim().split(/\s+/).filter(function (klass) {
62765 return klass.length && !/^tag-/.test(klass);
62766 }).map(function (klass) {
62767 // special overrides for some perimeter strokes
62768 return klass === 'line' || klass === 'area' ? overrideGeometry || klass : klass;
62769 }); // pick at most one primary classification tag..
62771 for (i = 0; i < primaries.length; i++) {
62774 if (!v || v === 'no') continue;
62776 if (k === 'piste:type') {
62777 // avoid a ':' in the class name
62779 } else if (k === 'building:part') {
62780 // avoid a ':' in the class name
62781 k = 'building_part';
62786 if (statuses.indexOf(v) !== -1) {
62787 // e.g. `railway=abandoned`
62789 classes.push('tag-' + k);
62791 classes.push('tag-' + k);
62792 classes.push('tag-' + k + '-' + v);
62799 for (i = 0; i < statuses.length; i++) {
62800 for (j = 0; j < primaries.length; j++) {
62801 k = statuses[i] + ':' + primaries[j]; // e.g. `demolished:building=yes`
62804 if (!v || v === 'no') continue;
62805 status = statuses[i];
62809 } // add at most one status tag, only if relates to primary tag..
62813 for (i = 0; i < statuses.length; i++) {
62816 if (!v || v === 'no') continue;
62819 // e.g. `railway=rail + abandoned=yes`
62821 } else if (primary && primary === v) {
62822 // e.g. `railway=rail + abandoned=railway`
62824 } else if (!primary && primaries.indexOf(v) !== -1) {
62825 // e.g. `abandoned=railway`
62828 classes.push('tag-' + v);
62829 } // else ignore e.g. `highway=path + abandoned=railway`
62837 classes.push('tag-status');
62838 classes.push('tag-status-' + status);
62839 } // add any secondary tags
62842 for (i = 0; i < secondaries.length; i++) {
62843 k = secondaries[i];
62845 if (!v || v === 'no' || k === primary) continue;
62846 classes.push('tag-' + k);
62847 classes.push('tag-' + k + '-' + v);
62848 } // For highways, look for surface tagging..
62851 if (primary === 'highway' && !osmPathHighwayTagValues[t.highway] || primary === 'aeroway') {
62852 var surface = t.highway === 'track' ? 'unpaved' : 'paved';
62857 if (k in osmPavedTags) {
62858 surface = osmPavedTags[k][v] ? 'paved' : 'unpaved';
62861 if (k in osmSemipavedTags && !!osmSemipavedTags[k][v]) {
62862 surface = 'semipaved';
62866 classes.push('tag-' + surface);
62867 } // If this is a wikidata-tagged item, add a class for that..
62870 var qid = t.wikidata || t['flag:wikidata'] || t['brand:wikidata'] || t['network:wikidata'] || t['operator:wikidata'];
62873 classes.push('tag-wikidata');
62876 return classes.join(' ').trim();
62879 tagClasses.tags = function (val) {
62880 if (!arguments.length) return _tags;
62888 // Patterns only work in Firefox when set directly on element.
62889 // (This is not a bug: https://bugzilla.mozilla.org/show_bug.cgi?id=750632)
62891 // tag - pattern name
62893 // tag - value - pattern name
62895 // tag - value - rules (optional tag-values, pattern name)
62896 // (matches earlier rules first, so fallback should be last entry)
62898 grave_yard: 'cemetery',
62899 fountain: 'water_standing'
62903 religion: 'christian',
62904 pattern: 'cemetery_christian'
62906 religion: 'buddhist',
62907 pattern: 'cemetery_buddhist'
62909 religion: 'muslim',
62910 pattern: 'cemetery_muslim'
62912 religion: 'jewish',
62913 pattern: 'cemetery_jewish'
62915 pattern: 'cemetery'
62917 construction: 'construction',
62918 farmland: 'farmland',
62919 farmyard: 'farmyard',
62921 leaf_type: 'broadleaved',
62922 pattern: 'forest_broadleaved'
62924 leaf_type: 'needleleaved',
62925 pattern: 'forest_needleleaved'
62927 leaf_type: 'leafless',
62928 pattern: 'forest_leafless'
62931 } // same as 'leaf_type:mixed'
62933 grave_yard: 'cemetery',
62936 pattern: 'golf_green'
62940 landfill: 'landfill',
62942 military: 'construction',
62943 orchard: 'orchard',
62945 vineyard: 'vineyard'
62949 grassland: 'grass',
62956 water: 'reservoir',
62957 pattern: 'water_standing'
62963 pattern: 'wetland_marsh'
62966 pattern: 'wetland_swamp'
62969 pattern: 'wetland_bog'
62971 wetland: 'reedbed',
62972 pattern: 'wetland_reedbed'
62977 leaf_type: 'broadleaved',
62978 pattern: 'forest_broadleaved'
62980 leaf_type: 'needleleaved',
62981 pattern: 'forest_needleleaved'
62983 leaf_type: 'leafless',
62984 pattern: 'forest_leafless'
62987 } // same as 'leaf_type:mixed'
63005 function svgTagPattern(tags) {
63006 // Skip pattern filling if this is a building (buildings don't get patterns applied)
63007 if (tags.building && tags.building !== 'no') {
63011 for (var tag in patterns) {
63012 var entityValue = tags[tag];
63013 if (!entityValue) continue;
63015 if (typeof patterns[tag] === 'string') {
63016 // extra short syntax (just tag) - pattern name
63017 return 'pattern-' + patterns[tag];
63019 var values = patterns[tag];
63021 for (var value in values) {
63022 if (entityValue !== value) continue;
63023 var rules = values[value];
63025 if (typeof rules === 'string') {
63026 // short syntax - pattern name
63027 return 'pattern-' + rules;
63028 } // long syntax - rule array
63031 for (var ruleKey in rules) {
63032 var rule = rules[ruleKey];
63035 for (var criterion in rule) {
63036 if (criterion !== 'pattern') {
63037 // reserved for pattern name
63038 // The only rule is a required tag-value pair
63039 var v = tags[criterion];
63041 if (!v || v !== rule[criterion]) {
63049 return 'pattern-' + rule.pattern;
63059 function svgAreas(projection, context) {
63060 function getPatternStyle(tags) {
63061 var imageID = svgTagPattern(tags);
63064 return 'url("#ideditor-' + imageID + '")';
63070 function drawTargets(selection, graph, entities, filter) {
63071 var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
63072 var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
63073 var getPath = svgPath(projection).geojson;
63074 var activeID = context.activeID();
63075 var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
63081 entities.forEach(function (way) {
63082 var features = svgSegmentWay(way, graph, activeID);
63083 data.targets.push.apply(data.targets, features.passive);
63084 data.nopes.push.apply(data.nopes, features.active);
63085 }); // Targets allow hover and vertex snapping
63087 var targetData = data.targets.filter(getPath);
63088 var targets = selection.selectAll('.area.target-allowed').filter(function (d) {
63089 return filter(d.properties.entity);
63090 }).data(targetData, function key(d) {
63094 targets.exit().remove();
63096 var segmentWasEdited = function segmentWasEdited(d) {
63097 var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
63099 if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
63103 return d.properties.nodes.some(function (n) {
63104 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
63109 targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
63110 return 'way area target target-allowed ' + targetClass + d.id;
63111 }).classed('segment-edited', segmentWasEdited); // NOPE
63113 var nopeData = data.nopes.filter(getPath);
63114 var nopes = selection.selectAll('.area.target-nope').filter(function (d) {
63115 return filter(d.properties.entity);
63116 }).data(nopeData, function key(d) {
63120 nopes.exit().remove(); // enter/update
63122 nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
63123 return 'way area target target-nope ' + nopeClass + d.id;
63124 }).classed('segment-edited', segmentWasEdited);
63127 function drawAreas(selection, graph, entities, filter) {
63128 var path = svgPath(projection, graph, true);
63131 var base = context.history().base();
63133 for (var i = 0; i < entities.length; i++) {
63134 var entity = entities[i];
63135 if (entity.geometry(graph) !== 'area') continue;
63136 multipolygon = osmIsOldMultipolygonOuterMember(entity, graph);
63138 if (multipolygon) {
63139 areas[multipolygon.id] = {
63140 entity: multipolygon.mergeTags(entity.tags),
63141 area: Math.abs(entity.area(graph))
63143 } else if (!areas[entity.id]) {
63144 areas[entity.id] = {
63146 area: Math.abs(entity.area(graph))
63151 var fills = Object.values(areas).filter(function hasPath(a) {
63152 return path(a.entity);
63154 fills.sort(function areaSort(a, b) {
63155 return b.area - a.area;
63157 fills = fills.map(function (a) {
63160 var strokes = fills.filter(function (area) {
63161 return area.type === 'way';
63169 var clipPaths = context.surface().selectAll('defs').selectAll('.clipPath-osm').filter(filter).data(data.clip, osmEntity.key);
63170 clipPaths.exit().remove();
63171 var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-osm').attr('id', function (entity) {
63172 return 'ideditor-' + entity.id + '-clippath';
63174 clipPathsEnter.append('path');
63175 clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', path);
63176 var drawLayer = selection.selectAll('.layer-osm.areas');
63177 var touchLayer = selection.selectAll('.layer-touch.areas'); // Draw areas..
63179 var areagroup = drawLayer.selectAll('g.areagroup').data(['fill', 'shadow', 'stroke']);
63180 areagroup = areagroup.enter().append('g').attr('class', function (d) {
63181 return 'areagroup area-' + d;
63182 }).merge(areagroup);
63183 var paths = areagroup.selectAll('path').filter(filter).data(function (layer) {
63184 return data[layer];
63186 paths.exit().remove();
63187 var fillpaths = selection.selectAll('.area-fill path.area').nodes();
63188 var bisect = d3_bisector(function (node) {
63189 return -node.__data__.area(graph);
63192 function sortedByArea(entity) {
63193 if (this._parent.__data__ === 'fill') {
63194 return fillpaths[bisect(fillpaths, -entity.area(graph))];
63198 paths = paths.enter().insert('path', sortedByArea).merge(paths).each(function (entity) {
63199 var layer = this.parentNode.__data__;
63200 this.setAttribute('class', entity.type + ' area ' + layer + ' ' + entity.id);
63202 if (layer === 'fill') {
63203 this.setAttribute('clip-path', 'url(#ideditor-' + entity.id + '-clippath)');
63204 this.style.fill = this.style.stroke = getPatternStyle(entity.tags);
63206 }).classed('added', function (d) {
63207 return !base.entities[d.id];
63208 }).classed('geometry-edited', function (d) {
63209 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
63210 }).classed('retagged', function (d) {
63211 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
63212 }).call(svgTagClasses()).attr('d', path); // Draw touch targets..
63214 touchLayer.call(drawTargets, graph, data.stroke, filter);
63220 var fastJsonStableStringify = function fastJsonStableStringify(data, opts) {
63221 if (!opts) opts = {};
63222 if (typeof opts === 'function') opts = {
63225 var cycles = typeof opts.cycles === 'boolean' ? opts.cycles : false;
63227 var cmp = opts.cmp && function (f) {
63228 return function (node) {
63229 return function (a, b) {
63238 return f(aobj, bobj);
63244 return function stringify(node) {
63245 if (node && node.toJSON && typeof node.toJSON === 'function') {
63246 node = node.toJSON();
63249 if (node === undefined) return;
63250 if (typeof node == 'number') return isFinite(node) ? '' + node : 'null';
63251 if (_typeof(node) !== 'object') return JSON.stringify(node);
63254 if (Array.isArray(node)) {
63257 for (i = 0; i < node.length; i++) {
63259 out += stringify(node[i]) || 'null';
63265 if (node === null) return 'null';
63267 if (seen.indexOf(node) !== -1) {
63268 if (cycles) return JSON.stringify('__cycle__');
63269 throw new TypeError('Converting circular structure to JSON');
63272 var seenIndex = seen.push(node) - 1;
63273 var keys = Object.keys(node).sort(cmp && cmp(node));
63276 for (i = 0; i < keys.length; i++) {
63278 var value = stringify(node[key]);
63279 if (!value) continue;
63280 if (out) out += ',';
63281 out += JSON.stringify(key) + ':' + value;
63284 seen.splice(seenIndex, 1);
63285 return '{' + out + '}';
63290 var $entries = objectToArray.entries;
63292 // `Object.entries` method
63293 // https://tc39.es/ecma262/#sec-object.entries
63294 $$2({ target: 'Object', stat: true }, {
63295 entries: function entries(O) {
63296 return $entries(O);
63300 var _marked = /*#__PURE__*/regeneratorRuntime.mark(gpxGen),
63301 _marked3 = /*#__PURE__*/regeneratorRuntime.mark(kmlGen);
63303 // cast array x into numbers
63304 // get the content of a text node, if any
63305 function nodeVal(x) {
63306 if (x && x.normalize) {
63310 return x && x.textContent || "";
63311 } // one Y child of X, if any, otherwise null
63314 function get1(x, y) {
63315 var n = x.getElementsByTagName(y);
63316 return n.length ? n[0] : null;
63319 function getLineStyle(extensions) {
63323 var lineStyle = get1(extensions, "line");
63326 var color = nodeVal(get1(lineStyle, "color")),
63327 opacity = parseFloat(nodeVal(get1(lineStyle, "opacity"))),
63328 width = parseFloat(nodeVal(get1(lineStyle, "width")));
63329 if (color) style.stroke = color;
63330 if (!isNaN(opacity)) style["stroke-opacity"] = opacity; // GPX width is in mm, convert to px with 96 px per inch
63332 if (!isNaN(width)) style["stroke-width"] = width * 96 / 25.4;
63337 } // get the contents of multiple text nodes, if present
63340 function getMulti(x, ys) {
63345 for (k = 0; k < ys.length; k++) {
63346 n = get1(x, ys[k]);
63347 if (n) o[ys[k]] = nodeVal(n);
63353 function getProperties$1(node) {
63354 var prop = getMulti(node, ["name", "cmt", "desc", "type", "time", "keywords"]); // Parse additional data from our Garmin extension(s)
63356 var extensions = node.getElementsByTagNameNS("http://www.garmin.com/xmlschemas/GpxExtensions/v3", "*");
63358 for (var i = 0; i < extensions.length; i++) {
63359 var extension = extensions[i]; // Ignore nested extensions, like those on routepoints or trackpoints
63361 if (extension.parentNode.parentNode === node) {
63362 prop[extension.tagName.replace(":", "_")] = nodeVal(extension);
63366 var links = node.getElementsByTagName("link");
63367 if (links.length) prop.links = [];
63369 for (var _i = 0; _i < links.length; _i++) {
63370 prop.links.push(Object.assign({
63371 href: links[_i].getAttribute("href")
63372 }, getMulti(links[_i], ["text", "type"])));
63378 function coordPair$1(x) {
63379 var ll = [parseFloat(x.getAttribute("lon")), parseFloat(x.getAttribute("lat"))];
63380 var ele = get1(x, "ele"); // handle namespaced attribute in browser
63382 var heart = get1(x, "gpxtpx:hr") || get1(x, "hr");
63383 var time = get1(x, "time");
63387 e = parseFloat(nodeVal(ele));
63396 time: time ? nodeVal(time) : null,
63401 result.extendedValues.push(["heart", parseFloat(nodeVal(heart))]);
63404 var extensions = get1(x, "extensions");
63406 if (extensions !== null) {
63407 for (var _i2 = 0, _arr = ["speed", "course", "hAcc", "vAcc"]; _i2 < _arr.length; _i2++) {
63408 var name = _arr[_i2];
63409 var v = parseFloat(nodeVal(get1(extensions, name)));
63412 result.extendedValues.push([name, v]);
63420 function getRoute(node) {
63421 var line = getPoints$1(node, "rtept");
63425 properties: Object.assign(getProperties$1(node), getLineStyle(get1(node, "extensions")), {
63429 type: "LineString",
63430 coordinates: line.line
63435 function getPoints$1(node, pointname) {
63436 var pts = node.getElementsByTagName(pointname);
63437 if (pts.length < 2) return; // Invalid line in GeoJSON
63441 var extendedValues = {};
63443 for (var i = 0; i < pts.length; i++) {
63444 var c = coordPair$1(pts[i]);
63445 line.push(c.coordinates);
63446 if (c.time) times.push(c.time);
63448 for (var j = 0; j < c.extendedValues.length; j++) {
63449 var _c$extendedValues$j = _slicedToArray(c.extendedValues[j], 2),
63450 name = _c$extendedValues$j[0],
63451 val = _c$extendedValues$j[1];
63453 var plural = name === "heart" ? name : name + "s";
63455 if (!extendedValues[plural]) {
63456 extendedValues[plural] = Array(pts.length).fill(null);
63459 extendedValues[plural][i] = val;
63466 extendedValues: extendedValues
63470 function getTrack(node) {
63471 var segments = node.getElementsByTagName("trkseg");
63474 var extractedLines = [];
63476 for (var i = 0; i < segments.length; i++) {
63477 var line = getPoints$1(segments[i], "trkpt");
63480 extractedLines.push(line);
63481 if (line.times && line.times.length) times.push(line.times);
63485 if (extractedLines.length === 0) return;
63486 var multi = extractedLines.length > 1;
63487 var properties = Object.assign(getProperties$1(node), getLineStyle(get1(node, "extensions")), {
63489 }, times.length ? {
63490 coordinateProperties: {
63491 times: multi ? times : times[0]
63495 for (var _i3 = 0; _i3 < extractedLines.length; _i3++) {
63496 var _line = extractedLines[_i3];
63497 track.push(_line.line);
63499 for (var _i4 = 0, _Object$entries = Object.entries(_line.extendedValues); _i4 < _Object$entries.length; _i4++) {
63500 var _Object$entries$_i = _slicedToArray(_Object$entries[_i4], 2),
63501 name = _Object$entries$_i[0],
63502 val = _Object$entries$_i[1];
63504 var props = properties;
63506 if (name === "heart") {
63507 if (!properties.coordinateProperties) {
63508 properties.coordinateProperties = {};
63511 props = properties.coordinateProperties;
63515 if (!props[name]) props[name] = extractedLines.map(function (line) {
63516 return new Array(line.line.length).fill(null);
63518 props[name][_i3] = val;
63527 properties: properties,
63528 geometry: multi ? {
63529 type: "MultiLineString",
63532 type: "LineString",
63533 coordinates: track[0]
63538 function getPoint(node) {
63541 properties: Object.assign(getProperties$1(node), getMulti(node, ["sym"])),
63544 coordinates: coordPair$1(node).coordinates
63549 function gpxGen(doc) {
63550 var tracks, routes, waypoints, i, feature, _i5, _feature, _i6;
63552 return regeneratorRuntime.wrap(function gpxGen$(_context) {
63554 switch (_context.prev = _context.next) {
63556 tracks = doc.getElementsByTagName("trk");
63557 routes = doc.getElementsByTagName("rte");
63558 waypoints = doc.getElementsByTagName("wpt");
63562 if (!(i < tracks.length)) {
63563 _context.next = 12;
63567 feature = getTrack(tracks[i]);
63586 if (!(_i5 < routes.length)) {
63587 _context.next = 21;
63591 _feature = getRoute(routes[_i5]);
63594 _context.next = 18;
63598 _context.next = 18;
63603 _context.next = 13;
63610 if (!(_i6 < waypoints.length)) {
63611 _context.next = 28;
63615 _context.next = 25;
63616 return getPoint(waypoints[_i6]);
63620 _context.next = 22;
63625 return _context.stop();
63631 function gpx(doc) {
63633 type: "FeatureCollection",
63634 features: Array.from(gpxGen(doc))
63638 var removeSpace = /\s*/g;
63639 var trimSpace = /^\s*|\s*$/g;
63640 var splitSpace = /\s+/; // generate a short, numeric hash of a string
63642 function okhash(x) {
63643 if (!x || !x.length) return 0;
63646 for (var i = 0; i < x.length; i++) {
63647 h = (h << 5) - h + x.charCodeAt(i) | 0;
63651 } // get one coordinate from a coordinate array, if any
63654 function coord1(v) {
63655 return v.replace(removeSpace, "").split(",").map(parseFloat);
63656 } // get all coordinates from a coordinate array as [[],[]]
63659 function coord(v) {
63660 return v.replace(trimSpace, "").split(splitSpace).map(coord1);
63663 function xml2str(node) {
63664 if (node.xml !== undefined) return node.xml;
63666 if (node.tagName) {
63667 var output = node.tagName;
63669 for (var i = 0; i < node.attributes.length; i++) {
63670 output += node.attributes[i].name + node.attributes[i].value;
63673 for (var _i9 = 0; _i9 < node.childNodes.length; _i9++) {
63674 output += xml2str(node.childNodes[_i9]);
63680 if (node.nodeName === "#text") {
63681 return (node.nodeValue || node.value || "").trim();
63684 if (node.nodeName === "#cdata-section") {
63685 return node.nodeValue;
63691 var geotypes = ["Polygon", "LineString", "Point", "Track", "gx:Track"];
63693 function kmlColor(properties, elem, prefix) {
63694 var v = nodeVal(get1(elem, "color")) || "";
63695 var colorProp = prefix == "stroke" || prefix === "fill" ? prefix : prefix + "-color";
63697 if (v.substr(0, 1) === "#") {
63701 if (v.length === 6 || v.length === 3) {
63702 properties[colorProp] = v;
63703 } else if (v.length === 8) {
63704 properties[prefix + "-opacity"] = parseInt(v.substr(0, 2), 16) / 255;
63705 properties[colorProp] = "#" + v.substr(6, 2) + v.substr(4, 2) + v.substr(2, 2);
63709 function numericProperty(properties, elem, source, target) {
63710 var val = parseFloat(nodeVal(get1(elem, source)));
63711 if (!isNaN(val)) properties[target] = val;
63714 function gxCoords(root) {
63715 var elems = root.getElementsByTagName("coord");
63718 if (elems.length === 0) elems = root.getElementsByTagName("gx:coord");
63720 for (var i = 0; i < elems.length; i++) {
63721 coords.push(nodeVal(elems[i]).split(" ").map(parseFloat));
63724 var timeElems = root.getElementsByTagName("when");
63726 for (var j = 0; j < timeElems.length; j++) {
63727 times.push(nodeVal(timeElems[j]));
63736 function getGeometry(root) {
63743 var coordTimes = [];
63745 if (get1(root, "MultiGeometry")) {
63746 return getGeometry(get1(root, "MultiGeometry"));
63749 if (get1(root, "MultiTrack")) {
63750 return getGeometry(get1(root, "MultiTrack"));
63753 if (get1(root, "gx:MultiTrack")) {
63754 return getGeometry(get1(root, "gx:MultiTrack"));
63757 for (i = 0; i < geotypes.length; i++) {
63758 geomNodes = root.getElementsByTagName(geotypes[i]);
63761 for (j = 0; j < geomNodes.length; j++) {
63762 geomNode = geomNodes[j];
63764 if (geotypes[i] === "Point") {
63767 coordinates: coord1(nodeVal(get1(geomNode, "coordinates")))
63769 } else if (geotypes[i] === "LineString") {
63771 type: "LineString",
63772 coordinates: coord(nodeVal(get1(geomNode, "coordinates")))
63774 } else if (geotypes[i] === "Polygon") {
63775 var rings = geomNode.getElementsByTagName("LinearRing"),
63778 for (k = 0; k < rings.length; k++) {
63779 coords.push(coord(nodeVal(get1(rings[k], "coordinates"))));
63784 coordinates: coords
63786 } else if (geotypes[i] === "Track" || geotypes[i] === "gx:Track") {
63787 var track = gxCoords(geomNode);
63789 type: "LineString",
63790 coordinates: track.coords
63792 if (track.times.length) coordTimes.push(track.times);
63800 coordTimes: coordTimes
63804 function getPlacemark(root, styleIndex, styleMapIndex, styleByHash) {
63805 var geomsAndTimes = getGeometry(root);
63807 var properties = {};
63808 var name = nodeVal(get1(root, "name"));
63809 var address = nodeVal(get1(root, "address"));
63810 var styleUrl = nodeVal(get1(root, "styleUrl"));
63811 var description = nodeVal(get1(root, "description"));
63812 var timeSpan = get1(root, "TimeSpan");
63813 var timeStamp = get1(root, "TimeStamp");
63814 var extendedData = get1(root, "ExtendedData");
63815 var iconStyle = get1(root, "IconStyle");
63816 var labelStyle = get1(root, "LabelStyle");
63817 var lineStyle = get1(root, "LineStyle");
63818 var polyStyle = get1(root, "PolyStyle");
63819 var visibility = get1(root, "visibility");
63820 if (name) properties.name = name;
63821 if (address) properties.address = address;
63824 if (styleUrl[0] !== "#") {
63825 styleUrl = "#" + styleUrl;
63828 properties.styleUrl = styleUrl;
63830 if (styleIndex[styleUrl]) {
63831 properties.styleHash = styleIndex[styleUrl];
63834 if (styleMapIndex[styleUrl]) {
63835 properties.styleMapHash = styleMapIndex[styleUrl];
63836 properties.styleHash = styleIndex[styleMapIndex[styleUrl].normal];
63837 } // Try to populate the lineStyle or polyStyle since we got the style hash
63840 var style = styleByHash[properties.styleHash];
63843 if (!iconStyle) iconStyle = get1(style, "IconStyle");
63844 if (!labelStyle) labelStyle = get1(style, "LabelStyle");
63845 if (!lineStyle) lineStyle = get1(style, "LineStyle");
63846 if (!polyStyle) polyStyle = get1(style, "PolyStyle");
63850 if (description) properties.description = description;
63853 var begin = nodeVal(get1(timeSpan, "begin"));
63854 var end = nodeVal(get1(timeSpan, "end"));
63855 properties.timespan = {
63862 properties.timestamp = nodeVal(get1(timeStamp, "when"));
63866 kmlColor(properties, iconStyle, "icon");
63867 numericProperty(properties, iconStyle, "scale", "icon-scale");
63868 numericProperty(properties, iconStyle, "heading", "icon-heading");
63869 var hotspot = get1(iconStyle, "hotSpot");
63872 var left = parseFloat(hotspot.getAttribute("x"));
63873 var top = parseFloat(hotspot.getAttribute("y"));
63874 if (!isNaN(left) && !isNaN(top)) properties["icon-offset"] = [left, top];
63877 var icon = get1(iconStyle, "Icon");
63880 var href = nodeVal(get1(icon, "href"));
63881 if (href) properties.icon = href;
63886 kmlColor(properties, labelStyle, "label");
63887 numericProperty(properties, labelStyle, "scale", "label-scale");
63891 kmlColor(properties, lineStyle, "stroke");
63892 numericProperty(properties, lineStyle, "width", "stroke-width");
63896 kmlColor(properties, polyStyle, "fill");
63897 var fill = nodeVal(get1(polyStyle, "fill"));
63898 var outline = nodeVal(get1(polyStyle, "outline"));
63899 if (fill) properties["fill-opacity"] = fill === "1" ? properties["fill-opacity"] || 1 : 0;
63900 if (outline) properties["stroke-opacity"] = outline === "1" ? properties["stroke-opacity"] || 1 : 0;
63903 if (extendedData) {
63904 var datas = extendedData.getElementsByTagName("Data"),
63905 simpleDatas = extendedData.getElementsByTagName("SimpleData");
63907 for (i = 0; i < datas.length; i++) {
63908 properties[datas[i].getAttribute("name")] = nodeVal(get1(datas[i], "value"));
63911 for (i = 0; i < simpleDatas.length; i++) {
63912 properties[simpleDatas[i].getAttribute("name")] = nodeVal(simpleDatas[i]);
63917 properties.visibility = nodeVal(visibility);
63920 if (geomsAndTimes.coordTimes.length) {
63921 properties.coordinateProperties = {
63922 times: geomsAndTimes.coordTimes.length === 1 ? geomsAndTimes.coordTimes[0] : geomsAndTimes.coordTimes
63928 geometry: geomsAndTimes.geoms.length === 0 ? null : geomsAndTimes.geoms.length === 1 ? geomsAndTimes.geoms[0] : {
63929 type: "GeometryCollection",
63930 geometries: geomsAndTimes.geoms
63932 properties: properties
63934 if (root.getAttribute("id")) feature.id = root.getAttribute("id");
63938 function kmlGen(doc) {
63939 var styleIndex, styleByHash, styleMapIndex, placemarks, styles, styleMaps, k, hash, l, pairs, pairsMap, m, j, feature;
63940 return regeneratorRuntime.wrap(function kmlGen$(_context3) {
63942 switch (_context3.prev = _context3.next) {
63944 // styleindex keeps track of hashed styles in order to match feature
63946 styleByHash = {}; // stylemapindex keeps track of style maps to expose in properties
63948 styleMapIndex = {}; // atomic geospatial types supported by KML - MultiGeometry is
63949 // handled separately
63950 // all root placemarks in the file
63952 placemarks = doc.getElementsByTagName("Placemark");
63953 styles = doc.getElementsByTagName("Style");
63954 styleMaps = doc.getElementsByTagName("StyleMap");
63956 for (k = 0; k < styles.length; k++) {
63957 hash = okhash(xml2str(styles[k])).toString(16);
63958 styleIndex["#" + styles[k].getAttribute("id")] = hash;
63959 styleByHash[hash] = styles[k];
63962 for (l = 0; l < styleMaps.length; l++) {
63963 styleIndex["#" + styleMaps[l].getAttribute("id")] = okhash(xml2str(styleMaps[l])).toString(16);
63964 pairs = styleMaps[l].getElementsByTagName("Pair");
63967 for (m = 0; m < pairs.length; m++) {
63968 pairsMap[nodeVal(get1(pairs[m], "key"))] = nodeVal(get1(pairs[m], "styleUrl"));
63971 styleMapIndex["#" + styleMaps[l].getAttribute("id")] = pairsMap;
63977 if (!(j < placemarks.length)) {
63978 _context3.next = 17;
63982 feature = getPlacemark(placemarks[j], styleIndex, styleMapIndex, styleByHash);
63985 _context3.next = 14;
63989 _context3.next = 14;
63994 _context3.next = 9;
63999 return _context3.stop();
64005 function kml(doc) {
64007 type: "FeatureCollection",
64008 features: Array.from(kmlGen(doc))
64012 var _initialized = false;
64013 var _enabled = false;
64017 function svgData(projection, context, dispatch) {
64018 var throttledRedraw = throttle(function () {
64019 dispatch.call('change');
64022 var _showLabels = true;
64023 var detected = utilDetect();
64024 var layer = select(null);
64035 if (_initialized) return; // run once
64040 function over(d3_event) {
64041 d3_event.stopPropagation();
64042 d3_event.preventDefault();
64043 d3_event.dataTransfer.dropEffect = 'copy';
64046 context.container().attr('dropzone', 'copy').on('drop.svgData', function (d3_event) {
64047 d3_event.stopPropagation();
64048 d3_event.preventDefault();
64049 if (!detected.filedrop) return;
64050 drawData.fileList(d3_event.dataTransfer.files);
64051 }).on('dragenter.svgData', over).on('dragexit.svgData', over).on('dragover.svgData', over);
64052 _initialized = true;
64055 function getService() {
64056 if (services.vectorTile && !_vtService) {
64057 _vtService = services.vectorTile;
64059 _vtService.event.on('loadedData', throttledRedraw);
64060 } else if (!services.vectorTile && _vtService) {
64067 function showLayer() {
64069 layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
64070 dispatch.call('change');
64074 function hideLayer() {
64075 throttledRedraw.cancel();
64076 layer.transition().duration(250).style('opacity', 0).on('end', layerOff);
64079 function layerOn() {
64080 layer.style('display', 'block');
64083 function layerOff() {
64084 layer.selectAll('.viewfield-group').remove();
64085 layer.style('display', 'none');
64086 } // ensure that all geojson features in a collection have IDs
64089 function ensureIDs(gj) {
64090 if (!gj) return null;
64092 if (gj.type === 'FeatureCollection') {
64093 for (var i = 0; i < gj.features.length; i++) {
64094 ensureFeatureID(gj.features[i]);
64097 ensureFeatureID(gj);
64101 } // ensure that each single Feature object has a unique ID
64104 function ensureFeatureID(feature) {
64105 if (!feature) return;
64106 feature.__featurehash__ = utilHashcode(fastJsonStableStringify(feature));
64108 } // Prefer an array of Features instead of a FeatureCollection
64111 function getFeatures(gj) {
64112 if (!gj) return [];
64114 if (gj.type === 'FeatureCollection') {
64115 return gj.features;
64121 function featureKey(d) {
64122 return d.__featurehash__;
64125 function isPolygon(d) {
64126 return d.geometry.type === 'Polygon' || d.geometry.type === 'MultiPolygon';
64129 function clipPathID(d) {
64130 return 'ideditor-data-' + d.__featurehash__ + '-clippath';
64133 function featureClasses(d) {
64134 return ['data' + d.__featurehash__, d.geometry.type, isPolygon(d) ? 'area' : '', d.__layerID__ || ''].filter(Boolean).join(' ');
64137 function drawData(selection) {
64138 var vtService = getService();
64139 var getPath = svgPath(projection).geojson;
64140 var getAreaPath = svgPath(projection, null, true).geojson;
64141 var hasData = drawData.hasData();
64142 layer = selection.selectAll('.layer-mapdata').data(_enabled && hasData ? [0] : []);
64143 layer.exit().remove();
64144 layer = layer.enter().append('g').attr('class', 'layer-mapdata').merge(layer);
64145 var surface = context.surface();
64146 if (!surface || surface.empty()) return; // not ready to draw yet, starting up
64149 var geoData, polygonData;
64151 if (_template && vtService) {
64152 // fetch data from vector tile service
64153 var sourceID = _template;
64154 vtService.loadTiles(sourceID, _template, projection);
64155 geoData = vtService.data(sourceID, projection);
64157 geoData = getFeatures(_geojson);
64160 geoData = geoData.filter(getPath);
64161 polygonData = geoData.filter(isPolygon); // Draw clip paths for polygons
64163 var clipPaths = surface.selectAll('defs').selectAll('.clipPath-data').data(polygonData, featureKey);
64164 clipPaths.exit().remove();
64165 var clipPathsEnter = clipPaths.enter().append('clipPath').attr('class', 'clipPath-data').attr('id', clipPathID);
64166 clipPathsEnter.append('path');
64167 clipPaths.merge(clipPathsEnter).selectAll('path').attr('d', getAreaPath); // Draw fill, shadow, stroke layers
64169 var datagroups = layer.selectAll('g.datagroup').data(['fill', 'shadow', 'stroke']);
64170 datagroups = datagroups.enter().append('g').attr('class', function (d) {
64171 return 'datagroup datagroup-' + d;
64172 }).merge(datagroups); // Draw paths
64179 var paths = datagroups.selectAll('path').data(function (layer) {
64180 return pathData[layer];
64181 }, featureKey); // exit
64183 paths.exit().remove(); // enter/update
64185 paths = paths.enter().append('path').attr('class', function (d) {
64186 var datagroup = this.parentNode.__data__;
64187 return 'pathdata ' + datagroup + ' ' + featureClasses(d);
64188 }).attr('clip-path', function (d) {
64189 var datagroup = this.parentNode.__data__;
64190 return datagroup === 'fill' ? 'url(#' + clipPathID(d) + ')' : null;
64191 }).merge(paths).attr('d', function (d) {
64192 var datagroup = this.parentNode.__data__;
64193 return datagroup === 'fill' ? getAreaPath(d) : getPath(d);
64196 layer.call(drawLabels, 'label-halo', geoData).call(drawLabels, 'label', geoData);
64198 function drawLabels(selection, textClass, data) {
64199 var labelPath = d3_geoPath(projection);
64200 var labelData = data.filter(function (d) {
64201 return _showLabels && d.properties && (d.properties.desc || d.properties.name);
64203 var labels = selection.selectAll('text.' + textClass).data(labelData, featureKey); // exit
64205 labels.exit().remove(); // enter/update
64207 labels = labels.enter().append('text').attr('class', function (d) {
64208 return textClass + ' ' + featureClasses(d);
64209 }).merge(labels).text(function (d) {
64210 return d.properties.desc || d.properties.name;
64211 }).attr('x', function (d) {
64212 var centroid = labelPath.centroid(d);
64213 return centroid[0] + 11;
64214 }).attr('y', function (d) {
64215 var centroid = labelPath.centroid(d);
64216 return centroid[1];
64221 function getExtension(fileName) {
64222 if (!fileName) return;
64223 var re = /\.(gpx|kml|(geo)?json)$/i;
64224 var match = fileName.toLowerCase().match(re);
64225 return match && match.length && match[0];
64228 function xmlToDom(textdata) {
64229 return new DOMParser().parseFromString(textdata, 'text/xml');
64232 drawData.setFile = function (extension, data) {
64239 switch (extension) {
64241 gj = gpx(xmlToDom(data));
64245 gj = kml(xmlToDom(data));
64250 gj = JSON.parse(data);
64256 if (Object.keys(gj).length) {
64257 _geojson = ensureIDs(gj);
64258 _src = extension + ' data file';
64262 dispatch.call('change');
64266 drawData.showLabels = function (val) {
64267 if (!arguments.length) return _showLabels;
64272 drawData.enabled = function (val) {
64273 if (!arguments.length) return _enabled;
64282 dispatch.call('change');
64286 drawData.hasData = function () {
64287 var gj = _geojson || {};
64288 return !!(_template || Object.keys(gj).length);
64291 drawData.template = function (val, src) {
64292 if (!arguments.length) return _template; // test source against OSM imagery blocklists..
64294 var osm = context.connection();
64297 var blocklists = osm.imageryBlocklists();
64302 for (var i = 0; i < blocklists.length; i++) {
64303 regex = blocklists[i];
64304 fail = regex.test(val);
64307 } // ensure at least one test was run.
64311 regex = /.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/;
64312 fail = regex.test(val);
64318 _geojson = null; // strip off the querystring/hash from the template,
64319 // it often includes the access token
64321 _src = src || 'vectortile:' + val.split(/[?#]/)[0];
64322 dispatch.call('change');
64326 drawData.geojson = function (gj, src) {
64327 if (!arguments.length) return _geojson;
64334 if (Object.keys(gj).length) {
64335 _geojson = ensureIDs(gj);
64336 _src = src || 'unknown.geojson';
64339 dispatch.call('change');
64343 drawData.fileList = function (fileList) {
64344 if (!arguments.length) return _fileList;
64346 _fileList = fileList;
64349 if (!fileList || !fileList.length) return this;
64350 var f = fileList[0];
64351 var extension = getExtension(f.name);
64352 var reader = new FileReader();
64354 reader.onload = function () {
64355 return function (e) {
64356 drawData.setFile(extension, e.target.result);
64360 reader.readAsText(f);
64364 drawData.url = function (url, defaultExtension) {
64368 _src = null; // strip off any querystring/hash from the url before checking extension
64370 var testUrl = url.split(/[?#]/)[0];
64371 var extension = getExtension(testUrl) || defaultExtension;
64375 d3_text(url).then(function (data) {
64376 drawData.setFile(extension, data);
64377 })["catch"](function () {
64381 drawData.template(url);
64387 drawData.getSrc = function () {
64391 drawData.fitZoom = function () {
64392 var features = getFeatures(_geojson);
64393 if (!features.length) return;
64394 var map = context.map();
64395 var viewport = map.trimmedExtent().polygon();
64396 var coords = features.reduce(function (coords, feature) {
64397 var geom = feature.geometry;
64398 if (!geom) return coords;
64399 var c = geom.coordinates;
64400 /* eslint-disable no-fallthrough */
64402 switch (geom.type) {
64410 case 'MultiPolygon':
64411 c = utilArrayFlatten(c);
64414 case 'MultiLineString':
64415 c = utilArrayFlatten(c);
64418 /* eslint-enable no-fallthrough */
64421 return utilArrayUnion(coords, c);
64424 if (!geoPolygonIntersectsPolygon(viewport, coords, true)) {
64425 var extent = geoExtent(d3_geoBounds({
64426 type: 'LineString',
64427 coordinates: coords
64429 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
64439 function svgDebug(projection, context) {
64440 function drawDebug(selection) {
64441 var showTile = context.getDebug('tile');
64442 var showCollision = context.getDebug('collision');
64443 var showImagery = context.getDebug('imagery');
64444 var showTouchTargets = context.getDebug('target');
64445 var showDownloaded = context.getDebug('downloaded');
64446 var debugData = [];
64455 if (showCollision) {
64469 if (showTouchTargets) {
64472 label: 'touchTargets'
64476 if (showDownloaded) {
64479 label: 'downloaded'
64483 var legend = context.container().select('.main-content').selectAll('.debug-legend').data(debugData.length ? [0] : []);
64484 legend.exit().remove();
64485 legend = legend.enter().append('div').attr('class', 'fillD debug-legend').merge(legend);
64486 var legendItems = legend.selectAll('.debug-legend-item').data(debugData, function (d) {
64489 legendItems.exit().remove();
64490 legendItems.enter().append('span').attr('class', function (d) {
64491 return "debug-legend-item ".concat(d["class"]);
64492 }).text(function (d) {
64495 var layer = selection.selectAll('.layer-debug').data(showImagery || showDownloaded ? [0] : []);
64496 layer.exit().remove();
64497 layer = layer.enter().append('g').attr('class', 'layer-debug').merge(layer); // imagery
64499 var extent = context.map().extent();
64500 _mainFileFetcher.get('imagery').then(function (d) {
64501 var hits = showImagery && d.query.bbox(extent.rectangle(), true) || [];
64502 var features = hits.map(function (d) {
64503 return d.features[d.id];
64505 var imagery = layer.selectAll('path.debug-imagery').data(features);
64506 imagery.exit().remove();
64507 imagery.enter().append('path').attr('class', 'debug-imagery debug orange');
64508 })["catch"](function () {
64512 var osm = context.connection();
64513 var dataDownloaded = [];
64515 if (osm && showDownloaded) {
64516 var rtree = osm.caches('get').tile.rtree;
64517 dataDownloaded = rtree.all().map(function (bbox) {
64525 coordinates: [[[bbox.minX, bbox.minY], [bbox.minX, bbox.maxY], [bbox.maxX, bbox.maxY], [bbox.maxX, bbox.minY], [bbox.minX, bbox.minY]]]
64531 var downloaded = layer.selectAll('path.debug-downloaded').data(showDownloaded ? dataDownloaded : []);
64532 downloaded.exit().remove();
64533 downloaded.enter().append('path').attr('class', 'debug-downloaded debug purple'); // update
64535 layer.selectAll('path').attr('d', svgPath(projection).geojson);
64536 } // This looks strange because `enabled` methods on other layers are
64537 // chainable getter/setters, and this one is just a getter.
64540 drawDebug.enabled = function () {
64541 if (!arguments.length) {
64542 return context.getDebug('tile') || context.getDebug('collision') || context.getDebug('imagery') || context.getDebug('target') || context.getDebug('downloaded');
64552 A standalone SVG element that contains only a `defs` sub-element. To be
64553 used once globally, since defs IDs must be unique within a document.
64556 function svgDefs(context) {
64557 var _defsSelection = select(null);
64559 var _spritesheetIds = ['iD-sprite', 'maki-sprite', 'temaki-sprite', 'fa-sprite', 'community-sprite'];
64561 function drawDefs(selection) {
64562 _defsSelection = selection.append('defs'); // add markers
64564 _defsSelection.append('marker').attr('id', 'ideditor-oneway-marker').attr('viewBox', '0 0 10 5').attr('refX', 2.5).attr('refY', 2.5).attr('markerWidth', 2).attr('markerHeight', 2).attr('markerUnits', 'strokeWidth').attr('orient', 'auto').append('path').attr('class', 'oneway-marker-path').attr('d', 'M 5,3 L 0,3 L 0,2 L 5,2 L 5,0 L 10,2.5 L 5,5 z').attr('stroke', 'none').attr('fill', '#000').attr('opacity', '0.75'); // SVG markers have to be given a colour where they're defined
64565 // (they can't inherit it from the line they're attached to),
64566 // so we need to manually define markers for each color of tag
64567 // (also, it's slightly nicer if we can control the
64568 // positioning for different tags)
64571 function addSidedMarker(name, color, offset) {
64572 _defsSelection.append('marker').attr('id', 'ideditor-sided-marker-' + name).attr('viewBox', '0 0 2 2').attr('refX', 1).attr('refY', -offset).attr('markerWidth', 1.5).attr('markerHeight', 1.5).attr('markerUnits', 'strokeWidth').attr('orient', 'auto').append('path').attr('class', 'sided-marker-path sided-marker-' + name + '-path').attr('d', 'M 0,0 L 1,1 L 2,0 z').attr('stroke', 'none').attr('fill', color);
64575 addSidedMarker('natural', 'rgb(170, 170, 170)', 0); // for a coastline, the arrows are (somewhat unintuitively) on
64576 // the water side, so let's color them blue (with a gap) to
64577 // give a stronger indication
64579 addSidedMarker('coastline', '#77dede', 1);
64580 addSidedMarker('waterway', '#77dede', 1); // barriers have a dashed line, and separating the triangle
64581 // from the line visually suits that
64583 addSidedMarker('barrier', '#ddd', 1);
64584 addSidedMarker('man_made', '#fff', 0);
64586 _defsSelection.append('marker').attr('id', 'ideditor-viewfield-marker').attr('viewBox', '0 0 16 16').attr('refX', 8).attr('refY', 16).attr('markerWidth', 4).attr('markerHeight', 4).attr('markerUnits', 'strokeWidth').attr('orient', 'auto').append('path').attr('class', 'viewfield-marker-path').attr('d', 'M 6,14 C 8,13.4 8,13.4 10,14 L 16,3 C 12,0 4,0 0,3 z').attr('fill', '#333').attr('fill-opacity', '0.75').attr('stroke', '#fff').attr('stroke-width', '0.5px').attr('stroke-opacity', '0.75');
64588 _defsSelection.append('marker').attr('id', 'ideditor-viewfield-marker-wireframe').attr('viewBox', '0 0 16 16').attr('refX', 8).attr('refY', 16).attr('markerWidth', 4).attr('markerHeight', 4).attr('markerUnits', 'strokeWidth').attr('orient', 'auto').append('path').attr('class', 'viewfield-marker-path').attr('d', 'M 6,14 C 8,13.4 8,13.4 10,14 L 16,3 C 12,0 4,0 0,3 z').attr('fill', 'none').attr('stroke', '#fff').attr('stroke-width', '0.5px').attr('stroke-opacity', '0.75'); // add patterns
64591 var patterns = _defsSelection.selectAll('pattern').data([// pattern name, pattern image name
64592 ['beach', 'dots'], ['construction', 'construction'], ['cemetery', 'cemetery'], ['cemetery_christian', 'cemetery_christian'], ['cemetery_buddhist', 'cemetery_buddhist'], ['cemetery_muslim', 'cemetery_muslim'], ['cemetery_jewish', 'cemetery_jewish'], ['farmland', 'farmland'], ['farmyard', 'farmyard'], ['forest', 'forest'], ['forest_broadleaved', 'forest_broadleaved'], ['forest_needleleaved', 'forest_needleleaved'], ['forest_leafless', 'forest_leafless'], ['golf_green', 'grass'], ['grass', 'grass'], ['landfill', 'landfill'], ['meadow', 'grass'], ['orchard', 'orchard'], ['pond', 'pond'], ['quarry', 'quarry'], ['scrub', 'bushes'], ['vineyard', 'vineyard'], ['water_standing', 'lines'], ['waves', 'waves'], ['wetland', 'wetland'], ['wetland_marsh', 'wetland_marsh'], ['wetland_swamp', 'wetland_swamp'], ['wetland_bog', 'wetland_bog'], ['wetland_reedbed', 'wetland_reedbed']]).enter().append('pattern').attr('id', function (d) {
64593 return 'ideditor-pattern-' + d[0];
64594 }).attr('width', 32).attr('height', 32).attr('patternUnits', 'userSpaceOnUse');
64596 patterns.append('rect').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('class', function (d) {
64597 return 'pattern-color-' + d[0];
64599 patterns.append('image').attr('x', 0).attr('y', 0).attr('width', 32).attr('height', 32).attr('xlink:href', function (d) {
64600 return context.imagePath('pattern/' + d[1] + '.png');
64601 }); // add clip paths
64603 _defsSelection.selectAll('clipPath').data([12, 18, 20, 32, 45]).enter().append('clipPath').attr('id', function (d) {
64604 return 'ideditor-clip-square-' + d;
64605 }).append('rect').attr('x', 0).attr('y', 0).attr('width', function (d) {
64607 }).attr('height', function (d) {
64609 }); // add symbol spritesheets
64612 addSprites(_spritesheetIds, true);
64615 function addSprites(ids, overrideColors) {
64616 _spritesheetIds = utilArrayUniq(_spritesheetIds.concat(ids));
64618 var spritesheets = _defsSelection.selectAll('.spritesheet').data(_spritesheetIds);
64620 spritesheets.enter().append('g').attr('class', function (d) {
64621 return 'spritesheet spritesheet-' + d;
64622 }).each(function (d) {
64623 var url = context.imagePath(d + '.svg');
64624 var node = select(this).node();
64625 svg(url).then(function (svg) {
64626 node.appendChild(select(svg.documentElement).attr('id', 'ideditor-' + d).node());
64628 if (overrideColors && d !== 'iD-sprite') {
64629 // allow icon colors to be overridden..
64630 select(node).selectAll('path').attr('fill', 'currentColor');
64632 })["catch"](function () {
64636 spritesheets.exit().remove();
64639 drawDefs.addSprites = addSprites;
64643 var _layerEnabled$2 = false;
64647 function svgKeepRight(projection, context, dispatch) {
64648 var throttledRedraw = throttle(function () {
64649 return dispatch.call('change');
64653 var touchLayer = select(null);
64654 var drawLayer = select(null);
64655 var layerVisible = false;
64657 function markerPath(selection, klass) {
64658 selection.attr('class', klass).attr('transform', 'translate(-4, -24)').attr('d', 'M11.6,6.2H7.1l1.4-5.1C8.6,0.6,8.1,0,7.5,0H2.2C1.7,0,1.3,0.3,1.3,0.8L0,10.2c-0.1,0.6,0.4,1.1,0.9,1.1h4.6l-1.8,7.6C3.6,19.4,4.1,20,4.7,20c0.3,0,0.6-0.2,0.8-0.5l6.9-11.9C12.7,7,12.3,6.2,11.6,6.2z');
64659 } // Loosely-coupled keepRight service for fetching issues.
64662 function getService() {
64663 if (services.keepRight && !_qaService$2) {
64664 _qaService$2 = services.keepRight;
64666 _qaService$2.on('loaded', throttledRedraw);
64667 } else if (!services.keepRight && _qaService$2) {
64668 _qaService$2 = null;
64671 return _qaService$2;
64672 } // Show the markers
64675 function editOn() {
64676 if (!layerVisible) {
64677 layerVisible = true;
64678 drawLayer.style('display', 'block');
64680 } // Immediately remove the markers and their touch targets
64683 function editOff() {
64684 if (layerVisible) {
64685 layerVisible = false;
64686 drawLayer.style('display', 'none');
64687 drawLayer.selectAll('.qaItem.keepRight').remove();
64688 touchLayer.selectAll('.qaItem.keepRight').remove();
64690 } // Enable the layer. This shows the markers and transitions them to visible.
64693 function layerOn() {
64695 drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
64696 return dispatch.call('change');
64698 } // Disable the layer. This transitions the layer invisible and then hides the markers.
64701 function layerOff() {
64702 throttledRedraw.cancel();
64703 drawLayer.interrupt();
64704 touchLayer.selectAll('.qaItem.keepRight').remove();
64705 drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
64707 dispatch.call('change');
64709 } // Update the issue markers
64712 function updateMarkers() {
64713 if (!layerVisible || !_layerEnabled$2) return;
64714 var service = getService();
64715 var selectedID = context.selectedErrorID();
64716 var data = service ? service.getItems(projection) : [];
64717 var getTransform = svgPointTransform(projection); // Draw markers..
64719 var markers = drawLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
64723 markers.exit().remove(); // enter
64725 var markersEnter = markers.enter().append('g').attr('class', function (d) {
64726 return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
64728 markersEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
64729 markersEnter.append('path').call(markerPath, 'shadow');
64730 markersEnter.append('use').attr('class', 'qaItem-fill').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').attr('xlink:href', '#iD-icon-bolt'); // update
64732 markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
64733 return d.id === selectedID;
64734 }).attr('transform', getTransform); // Draw targets..
64736 if (touchLayer.empty()) return;
64737 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
64738 var targets = touchLayer.selectAll('.qaItem.keepRight').data(data, function (d) {
64742 targets.exit().remove(); // enter/update
64744 targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
64745 return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
64746 }).attr('transform', getTransform);
64748 function sortY(a, b) {
64749 return a.id === selectedID ? 1 : b.id === selectedID ? -1 : a.severity === 'error' && b.severity !== 'error' ? 1 : b.severity === 'error' && a.severity !== 'error' ? -1 : b.loc[1] - a.loc[1];
64751 } // Draw the keepRight layer and schedule loading issues and updating markers.
64754 function drawKeepRight(selection) {
64755 var service = getService();
64756 var surface = context.surface();
64758 if (surface && !surface.empty()) {
64759 touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
64762 drawLayer = selection.selectAll('.layer-keepRight').data(service ? [0] : []);
64763 drawLayer.exit().remove();
64764 drawLayer = drawLayer.enter().append('g').attr('class', 'layer-keepRight').style('display', _layerEnabled$2 ? 'block' : 'none').merge(drawLayer);
64766 if (_layerEnabled$2) {
64767 if (service && ~~context.map().zoom() >= minZoom) {
64769 service.loadIssues(projection);
64775 } // Toggles the layer on and off
64778 drawKeepRight.enabled = function (val) {
64779 if (!arguments.length) return _layerEnabled$2;
64780 _layerEnabled$2 = val;
64782 if (_layerEnabled$2) {
64787 if (context.selectedErrorID()) {
64788 context.enter(modeBrowse(context));
64792 dispatch.call('change');
64796 drawKeepRight.supported = function () {
64797 return !!getService();
64800 return drawKeepRight;
64803 function svgGeolocate(projection) {
64804 var layer = select(null);
64809 if (svgGeolocate.initialized) return; // run once
64811 svgGeolocate.enabled = false;
64812 svgGeolocate.initialized = true;
64815 function showLayer() {
64816 layer.style('display', 'block');
64819 function hideLayer() {
64820 layer.transition().duration(250).style('opacity', 0);
64823 function layerOn() {
64824 layer.style('opacity', 0).transition().duration(250).style('opacity', 1);
64827 function layerOff() {
64828 layer.style('display', 'none');
64831 function transform(d) {
64832 return svgPointTransform(projection)(d);
64835 function accuracy(accuracy, loc) {
64836 // converts accuracy to pixels...
64837 var degreesRadius = geoMetersToLat(accuracy),
64838 tangentLoc = [loc[0], loc[1] + degreesRadius],
64839 projectedTangent = projection(tangentLoc),
64840 projectedLoc = projection([loc[0], loc[1]]); // southern most point will have higher pixel value...
64842 return Math.round(projectedLoc[1] - projectedTangent[1]).toString();
64845 function update() {
64846 var geolocation = {
64847 loc: [_position.coords.longitude, _position.coords.latitude]
64849 var groups = layer.selectAll('.geolocations').selectAll('.geolocation').data([geolocation]);
64850 groups.exit().remove();
64851 var pointsEnter = groups.enter().append('g').attr('class', 'geolocation');
64852 pointsEnter.append('circle').attr('class', 'geolocate-radius').attr('dx', '0').attr('dy', '0').attr('fill', 'rgb(15,128,225)').attr('fill-opacity', '0.3').attr('r', '0');
64853 pointsEnter.append('circle').attr('dx', '0').attr('dy', '0').attr('fill', 'rgb(15,128,225)').attr('stroke', 'white').attr('stroke-width', '1.5').attr('r', '6');
64854 groups.merge(pointsEnter).attr('transform', transform);
64855 layer.select('.geolocate-radius').attr('r', accuracy(_position.coords.accuracy, geolocation.loc));
64858 function drawLocation(selection) {
64859 var enabled = svgGeolocate.enabled;
64860 layer = selection.selectAll('.layer-geolocate').data([0]);
64861 layer.exit().remove();
64862 var layerEnter = layer.enter().append('g').attr('class', 'layer-geolocate').style('display', enabled ? 'block' : 'none');
64863 layerEnter.append('g').attr('class', 'geolocations');
64864 layer = layerEnter.merge(layer);
64873 drawLocation.enabled = function (position, enabled) {
64874 if (!arguments.length) return svgGeolocate.enabled;
64875 _position = position;
64876 svgGeolocate.enabled = enabled;
64878 if (svgGeolocate.enabled) {
64889 return drawLocation;
64892 function svgLabels(projection, context) {
64893 var path = d3_geoPath(projection);
64894 var detected = utilDetect();
64895 var baselineHack = detected.ie || detected.browser.toLowerCase() === 'edge' || detected.browser.toLowerCase() === 'firefox' && detected.version >= 70;
64897 var _rdrawn = new RBush();
64899 var _rskipped = new RBush();
64901 var _textWidthCache = {};
64902 var _entitybboxes = {}; // Listed from highest to lowest priority
64904 var labelStack = [['line', 'aeroway', '*', 12], ['line', 'highway', 'motorway', 12], ['line', 'highway', 'trunk', 12], ['line', 'highway', 'primary', 12], ['line', 'highway', 'secondary', 12], ['line', 'highway', 'tertiary', 12], ['line', 'highway', '*', 12], ['line', 'railway', '*', 12], ['line', 'waterway', '*', 12], ['area', 'aeroway', '*', 12], ['area', 'amenity', '*', 12], ['area', 'building', '*', 12], ['area', 'historic', '*', 12], ['area', 'leisure', '*', 12], ['area', 'man_made', '*', 12], ['area', 'natural', '*', 12], ['area', 'shop', '*', 12], ['area', 'tourism', '*', 12], ['area', 'camp_site', '*', 12], ['point', 'aeroway', '*', 10], ['point', 'amenity', '*', 10], ['point', 'building', '*', 10], ['point', 'historic', '*', 10], ['point', 'leisure', '*', 10], ['point', 'man_made', '*', 10], ['point', 'natural', '*', 10], ['point', 'shop', '*', 10], ['point', 'tourism', '*', 10], ['point', 'camp_site', '*', 10], ['line', 'name', '*', 12], ['area', 'name', '*', 12], ['point', 'name', '*', 10]];
64906 function shouldSkipIcon(preset) {
64907 var noIcons = ['building', 'landuse', 'natural'];
64908 return noIcons.some(function (s) {
64909 return preset.id.indexOf(s) >= 0;
64913 function get(array, prop) {
64914 return function (d, i) {
64915 return array[i][prop];
64919 function textWidth(text, size, elem) {
64920 var c = _textWidthCache[size];
64921 if (!c) c = _textWidthCache[size] = {};
64926 c[text] = elem.getComputedTextLength();
64929 var str = encodeURIComponent(text).match(/%[CDEFcdef]/g);
64931 if (str === null) {
64932 return size / 3 * 2 * text.length;
64934 return size / 3 * (2 * text.length + str.length);
64939 function drawLinePaths(selection, entities, filter, classes, labels) {
64940 var paths = selection.selectAll('path').filter(filter).data(entities, osmEntity.key); // exit
64942 paths.exit().remove(); // enter/update
64944 paths.enter().append('path').style('stroke-width', get(labels, 'font-size')).attr('id', function (d) {
64945 return 'ideditor-labelpath-' + d.id;
64946 }).attr('class', classes).merge(paths).attr('d', get(labels, 'lineString'));
64949 function drawLineLabels(selection, entities, filter, classes, labels) {
64950 var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64952 texts.exit().remove(); // enter
64954 texts.enter().append('text').attr('class', function (d, i) {
64955 return classes + ' ' + labels[i].classes + ' ' + d.id;
64956 }).attr('dy', baselineHack ? '0.35em' : null).append('textPath').attr('class', 'textpath'); // update
64958 selection.selectAll('text.' + classes).selectAll('.textpath').filter(filter).data(entities, osmEntity.key).attr('startOffset', '50%').attr('xlink:href', function (d) {
64959 return '#ideditor-labelpath-' + d.id;
64960 }).text(utilDisplayNameForPath);
64963 function drawPointLabels(selection, entities, filter, classes, labels) {
64964 var texts = selection.selectAll('text.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64966 texts.exit().remove(); // enter/update
64968 texts.enter().append('text').attr('class', function (d, i) {
64969 return classes + ' ' + labels[i].classes + ' ' + d.id;
64970 }).merge(texts).attr('x', get(labels, 'x')).attr('y', get(labels, 'y')).style('text-anchor', get(labels, 'textAnchor')).text(utilDisplayName).each(function (d, i) {
64971 textWidth(utilDisplayName(d), labels[i].height, this);
64975 function drawAreaLabels(selection, entities, filter, classes, labels) {
64976 entities = entities.filter(hasText);
64977 labels = labels.filter(hasText);
64978 drawPointLabels(selection, entities, filter, classes, labels);
64980 function hasText(d, i) {
64981 return labels[i].hasOwnProperty('x') && labels[i].hasOwnProperty('y');
64985 function drawAreaIcons(selection, entities, filter, classes, labels) {
64986 var icons = selection.selectAll('use.' + classes).filter(filter).data(entities, osmEntity.key); // exit
64988 icons.exit().remove(); // enter/update
64990 icons.enter().append('use').attr('class', 'icon ' + classes).attr('width', '17px').attr('height', '17px').merge(icons).attr('transform', get(labels, 'transform')).attr('xlink:href', function (d) {
64991 var preset = _mainPresetIndex.match(d, context.graph());
64992 var picon = preset && preset.icon;
64997 var isMaki = /^maki-/.test(picon);
64998 return '#' + picon + (isMaki ? '-15' : '');
65003 function drawCollisionBoxes(selection, rtree, which) {
65004 var classes = 'debug ' + which + ' ' + (which === 'debug-skipped' ? 'orange' : 'yellow');
65007 if (context.getDebug('collision')) {
65008 gj = rtree.all().map(function (d) {
65011 coordinates: [[[d.minX, d.minY], [d.maxX, d.minY], [d.maxX, d.maxY], [d.minX, d.maxY], [d.minX, d.minY]]]
65016 var boxes = selection.selectAll('.' + which).data(gj); // exit
65018 boxes.exit().remove(); // enter/update
65020 boxes.enter().append('path').attr('class', classes).merge(boxes).attr('d', d3_geoPath());
65023 function drawLabels(selection, graph, entities, filter, dimensions, fullRedraw) {
65024 var wireframe = context.surface().classed('fill-wireframe');
65025 var zoom = geoScaleToZoom(projection.scale());
65026 var labelable = [];
65027 var renderNodeAs = {};
65028 var i, j, k, entity, geometry;
65030 for (i = 0; i < labelStack.length; i++) {
65031 labelable.push([]);
65039 _entitybboxes = {};
65041 for (i = 0; i < entities.length; i++) {
65042 entity = entities[i];
65043 var toRemove = [].concat(_entitybboxes[entity.id] || []).concat(_entitybboxes[entity.id + 'I'] || []);
65045 for (j = 0; j < toRemove.length; j++) {
65046 _rdrawn.remove(toRemove[j]);
65048 _rskipped.remove(toRemove[j]);
65051 } // Loop through all the entities to do some preprocessing
65054 for (i = 0; i < entities.length; i++) {
65055 entity = entities[i];
65056 geometry = entity.geometry(graph); // Insert collision boxes around interesting points/vertices
65058 if (geometry === 'point' || geometry === 'vertex' && isInterestingVertex(entity)) {
65059 var hasDirections = entity.directions(graph, projection).length;
65062 if (!wireframe && geometry === 'point' && !(zoom >= 18 && hasDirections)) {
65063 renderNodeAs[entity.id] = 'point';
65064 markerPadding = 20; // extra y for marker height
65066 renderNodeAs[entity.id] = 'vertex';
65070 var coord = projection(entity.loc);
65071 var nodePadding = 10;
65073 minX: coord[0] - nodePadding,
65074 minY: coord[1] - nodePadding - markerPadding,
65075 maxX: coord[0] + nodePadding,
65076 maxY: coord[1] + nodePadding
65078 doInsert(bbox, entity.id + 'P');
65079 } // From here on, treat vertices like points
65082 if (geometry === 'vertex') {
65083 geometry = 'point';
65084 } // Determine which entities are label-able
65087 var preset = geometry === 'area' && _mainPresetIndex.match(entity, graph);
65088 var icon = preset && !shouldSkipIcon(preset) && preset.icon;
65089 if (!icon && !utilDisplayName(entity)) continue;
65091 for (k = 0; k < labelStack.length; k++) {
65092 var matchGeom = labelStack[k][0];
65093 var matchKey = labelStack[k][1];
65094 var matchVal = labelStack[k][2];
65095 var hasVal = entity.tags[matchKey];
65097 if (geometry === matchGeom && hasVal && (matchVal === '*' || matchVal === hasVal)) {
65098 labelable[k].push(entity);
65113 }; // Try and find a valid label for labellable entities
65115 for (k = 0; k < labelable.length; k++) {
65116 var fontSize = labelStack[k][3];
65118 for (i = 0; i < labelable[k].length; i++) {
65119 entity = labelable[k][i];
65120 geometry = entity.geometry(graph);
65121 var getName = geometry === 'line' ? utilDisplayNameForPath : utilDisplayName;
65122 var name = getName(entity);
65123 var width = name && textWidth(name, fontSize);
65126 if (geometry === 'point' || geometry === 'vertex') {
65127 // no point or vertex labels in wireframe mode
65128 // no vertex labels at low zooms (vertices have no icons)
65129 if (wireframe) continue;
65130 var renderAs = renderNodeAs[entity.id];
65131 if (renderAs === 'vertex' && zoom < 17) continue;
65132 p = getPointLabel(entity, width, fontSize, renderAs);
65133 } else if (geometry === 'line') {
65134 p = getLineLabel(entity, width, fontSize);
65135 } else if (geometry === 'area') {
65136 p = getAreaLabel(entity, width, fontSize);
65140 if (geometry === 'vertex') {
65141 geometry = 'point';
65142 } // treat vertex like point
65145 p.classes = geometry + ' tag-' + labelStack[k][1];
65146 positions[geometry].push(p);
65147 labelled[geometry].push(entity);
65152 function isInterestingVertex(entity) {
65153 var selectedIDs = context.selectedIDs();
65154 return entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || selectedIDs.indexOf(entity.id) !== -1 || graph.parentWays(entity).some(function (parent) {
65155 return selectedIDs.indexOf(parent.id) !== -1;
65159 function getPointLabel(entity, width, height, geometry) {
65160 var y = geometry === 'point' ? -12 : 0;
65161 var pointOffsets = {
65162 ltr: [15, y, 'start'],
65163 rtl: [-15, y, 'end']
65165 var textDirection = _mainLocalizer.textDirection();
65166 var coord = projection(entity.loc);
65167 var textPadding = 2;
65168 var offset = pointOffsets[textDirection];
65172 x: coord[0] + offset[0],
65173 y: coord[1] + offset[1],
65174 textAnchor: offset[2]
65175 }; // insert a collision box for the text label..
65179 if (textDirection === 'rtl') {
65181 minX: p.x - width - textPadding,
65182 minY: p.y - height / 2 - textPadding,
65183 maxX: p.x + textPadding,
65184 maxY: p.y + height / 2 + textPadding
65188 minX: p.x - textPadding,
65189 minY: p.y - height / 2 - textPadding,
65190 maxX: p.x + width + textPadding,
65191 maxY: p.y + height / 2 + textPadding
65195 if (tryInsert([bbox], entity.id, true)) {
65200 function getLineLabel(entity, width, height) {
65201 var viewport = geoExtent(context.projection.clipExtent()).polygon();
65202 var points = graph.childNodes(entity).map(function (node) {
65203 return projection(node.loc);
65205 var length = geoPathLength(points);
65206 if (length < width + 20) return; // % along the line to attempt to place the label
65208 var lineOffsets = [50, 45, 55, 40, 60, 35, 65, 30, 70, 25, 75, 20, 80, 15, 95, 10, 90, 5, 95];
65211 for (var i = 0; i < lineOffsets.length; i++) {
65212 var offset = lineOffsets[i];
65213 var middle = offset / 100 * length;
65214 var start = middle - width / 2;
65215 if (start < 0 || start + width > length) continue; // generate subpath and ignore paths that are invalid or don't cross viewport.
65217 var sub = subpath(points, start, start + width);
65219 if (!sub || !geoPolygonIntersectsPolygon(viewport, sub, true)) {
65223 var isReverse = reverse(sub);
65226 sub = sub.reverse();
65230 var boxsize = (height + 2) / 2;
65232 for (var j = 0; j < sub.length - 1; j++) {
65234 var b = sub[j + 1]; // split up the text into small collision boxes
65236 var num = Math.max(1, Math.floor(geoVecLength(a, b) / boxsize / 2));
65238 for (var box = 0; box < num; box++) {
65239 var p = geoVecInterp(a, b, box / num);
65240 var x0 = p[0] - boxsize - padding;
65241 var y0 = p[1] - boxsize - padding;
65242 var x1 = p[0] + boxsize + padding;
65243 var y1 = p[1] + boxsize + padding;
65245 minX: Math.min(x0, x1),
65246 minY: Math.min(y0, y1),
65247 maxX: Math.max(x0, x1),
65248 maxY: Math.max(y0, y1)
65253 if (tryInsert(bboxes, entity.id, false)) {
65256 'font-size': height + 2,
65257 lineString: lineString(sub),
65258 startOffset: offset + '%'
65263 function reverse(p) {
65264 var angle = Math.atan2(p[1][1] - p[0][1], p[1][0] - p[0][0]);
65265 return !(p[0][0] < p[p.length - 1][0] && angle < Math.PI / 2 && angle > -Math.PI / 2);
65268 function lineString(points) {
65269 return 'M' + points.join('L');
65272 function subpath(points, from, to) {
65274 var start, end, i0, i1;
65276 for (var i = 0; i < points.length - 1; i++) {
65278 var b = points[i + 1];
65279 var current = geoVecLength(a, b);
65282 if (!start && sofar + current >= from) {
65283 portion = (from - sofar) / current;
65284 start = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
65288 if (!end && sofar + current >= to) {
65289 portion = (to - sofar) / current;
65290 end = [a[0] + portion * (b[0] - a[0]), a[1] + portion * (b[1] - a[1])];
65297 var result = points.slice(i0, i1);
65298 result.unshift(start);
65304 function getAreaLabel(entity, width, height) {
65305 var centroid = path.centroid(entity.asGeoJSON(graph));
65306 var extent = entity.extent(graph);
65307 var areaWidth = projection(extent[1])[0] - projection(extent[0])[0];
65308 if (isNaN(centroid[0]) || areaWidth < 20) return;
65309 var preset = _mainPresetIndex.match(entity, context.graph());
65310 var picon = preset && preset.icon;
65316 // icon and label..
65318 addLabel(iconSize + padding);
65328 function addIcon() {
65329 var iconX = centroid[0] - iconSize / 2;
65330 var iconY = centroid[1] - iconSize / 2;
65334 maxX: iconX + iconSize,
65335 maxY: iconY + iconSize
65338 if (tryInsert([bbox], entity.id + 'I', true)) {
65339 p.transform = 'translate(' + iconX + ',' + iconY + ')';
65346 function addLabel(yOffset) {
65347 if (width && areaWidth >= width + 20) {
65348 var labelX = centroid[0];
65349 var labelY = centroid[1] + yOffset;
65351 minX: labelX - width / 2 - padding,
65352 minY: labelY - height / 2 - padding,
65353 maxX: labelX + width / 2 + padding,
65354 maxY: labelY + height / 2 + padding
65357 if (tryInsert([bbox], entity.id, true)) {
65360 p.textAnchor = 'middle';
65368 } // force insert a singular bounding box
65369 // singular box only, no array, id better be unique
65372 function doInsert(bbox, id) {
65374 var oldbox = _entitybboxes[id];
65377 _rdrawn.remove(oldbox);
65380 _entitybboxes[id] = bbox;
65382 _rdrawn.insert(bbox);
65385 function tryInsert(bboxes, id, saveSkipped) {
65386 var skipped = false;
65388 for (var i = 0; i < bboxes.length; i++) {
65389 var bbox = bboxes[i];
65390 bbox.id = id; // Check that label is visible
65392 if (bbox.minX < 0 || bbox.minY < 0 || bbox.maxX > dimensions[0] || bbox.maxY > dimensions[1]) {
65397 if (_rdrawn.collides(bbox)) {
65403 _entitybboxes[id] = bboxes;
65407 _rskipped.load(bboxes);
65410 _rdrawn.load(bboxes);
65416 var layer = selection.selectAll('.layer-osm.labels');
65417 layer.selectAll('.labels-group').data(['halo', 'label', 'debug']).enter().append('g').attr('class', function (d) {
65418 return 'labels-group ' + d;
65420 var halo = layer.selectAll('.labels-group.halo');
65421 var label = layer.selectAll('.labels-group.label');
65422 var debug = layer.selectAll('.labels-group.debug'); // points
65424 drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
65425 drawPointLabels(halo, labelled.point, filter, 'pointlabel-halo', positions.point); // lines
65427 drawLinePaths(layer, labelled.line, filter, '', positions.line);
65428 drawLineLabels(label, labelled.line, filter, 'linelabel', positions.line);
65429 drawLineLabels(halo, labelled.line, filter, 'linelabel-halo', positions.line); // areas
65431 drawAreaLabels(label, labelled.area, filter, 'arealabel', positions.area);
65432 drawAreaLabels(halo, labelled.area, filter, 'arealabel-halo', positions.area);
65433 drawAreaIcons(label, labelled.area, filter, 'areaicon', positions.area);
65434 drawAreaIcons(halo, labelled.area, filter, 'areaicon-halo', positions.area); // debug
65436 drawCollisionBoxes(debug, _rskipped, 'debug-skipped');
65437 drawCollisionBoxes(debug, _rdrawn, 'debug-drawn');
65438 layer.call(filterLabels);
65441 function filterLabels(selection) {
65442 var drawLayer = selection.selectAll('.layer-osm.labels');
65443 var layers = drawLayer.selectAll('.labels-group.halo, .labels-group.label');
65444 layers.selectAll('.nolabel').classed('nolabel', false);
65445 var mouse = context.map().mouse();
65446 var graph = context.graph();
65447 var selectedIDs = context.selectedIDs();
65449 var pad, bbox; // hide labels near the mouse
65454 minX: mouse[0] - pad,
65455 minY: mouse[1] - pad,
65456 maxX: mouse[0] + pad,
65457 maxY: mouse[1] + pad
65460 var nearMouse = _rdrawn.search(bbox).map(function (entity) {
65464 ids.push.apply(ids, nearMouse);
65465 } // hide labels on selected nodes (they look weird when dragging / haloed)
65468 for (var i = 0; i < selectedIDs.length; i++) {
65469 var entity = graph.hasEntity(selectedIDs[i]);
65471 if (entity && entity.type === 'node') {
65472 ids.push(selectedIDs[i]);
65476 layers.selectAll(utilEntitySelector(ids)).classed('nolabel', true); // draw the mouse bbox if debugging is on..
65478 var debug = selection.selectAll('.labels-group.debug');
65481 if (context.getDebug('collision')) {
65484 coordinates: [[[bbox.minX, bbox.minY], [bbox.maxX, bbox.minY], [bbox.maxX, bbox.maxY], [bbox.minX, bbox.maxY], [bbox.minX, bbox.minY]]]
65488 var box = debug.selectAll('.debug-mouse').data(gj); // exit
65490 box.exit().remove(); // enter/update
65492 box.enter().append('path').attr('class', 'debug debug-mouse yellow').merge(box).attr('d', d3_geoPath());
65495 var throttleFilterLabels = throttle(filterLabels, 100);
65497 drawLabels.observe = function (selection) {
65498 var listener = function listener() {
65499 throttleFilterLabels(selection);
65502 selection.on('mousemove.hidelabels', listener);
65503 context.on('enter.hidelabels', listener);
65506 drawLabels.off = function (selection) {
65507 throttleFilterLabels.cancel();
65508 selection.on('mousemove.hidelabels', null);
65509 context.on('enter.hidelabels', null);
65515 var _layerEnabled$1 = false;
65519 function svgImproveOSM(projection, context, dispatch) {
65520 var throttledRedraw = throttle(function () {
65521 return dispatch.call('change');
65525 var touchLayer = select(null);
65526 var drawLayer = select(null);
65527 var layerVisible = false;
65529 function markerPath(selection, klass) {
65530 selection.attr('class', klass).attr('transform', 'translate(-10, -28)').attr('points', '16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6');
65531 } // Loosely-coupled improveOSM service for fetching issues
65534 function getService() {
65535 if (services.improveOSM && !_qaService$1) {
65536 _qaService$1 = services.improveOSM;
65538 _qaService$1.on('loaded', throttledRedraw);
65539 } else if (!services.improveOSM && _qaService$1) {
65540 _qaService$1 = null;
65543 return _qaService$1;
65544 } // Show the markers
65547 function editOn() {
65548 if (!layerVisible) {
65549 layerVisible = true;
65550 drawLayer.style('display', 'block');
65552 } // Immediately remove the markers and their touch targets
65555 function editOff() {
65556 if (layerVisible) {
65557 layerVisible = false;
65558 drawLayer.style('display', 'none');
65559 drawLayer.selectAll('.qaItem.improveOSM').remove();
65560 touchLayer.selectAll('.qaItem.improveOSM').remove();
65562 } // Enable the layer. This shows the markers and transitions them to visible.
65565 function layerOn() {
65567 drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
65568 return dispatch.call('change');
65570 } // Disable the layer. This transitions the layer invisible and then hides the markers.
65573 function layerOff() {
65574 throttledRedraw.cancel();
65575 drawLayer.interrupt();
65576 touchLayer.selectAll('.qaItem.improveOSM').remove();
65577 drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
65579 dispatch.call('change');
65581 } // Update the issue markers
65584 function updateMarkers() {
65585 if (!layerVisible || !_layerEnabled$1) return;
65586 var service = getService();
65587 var selectedID = context.selectedErrorID();
65588 var data = service ? service.getItems(projection) : [];
65589 var getTransform = svgPointTransform(projection); // Draw markers..
65591 var markers = drawLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
65595 markers.exit().remove(); // enter
65597 var markersEnter = markers.enter().append('g').attr('class', function (d) {
65598 return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
65600 markersEnter.append('polygon').call(markerPath, 'shadow');
65601 markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
65602 markersEnter.append('polygon').attr('fill', 'currentColor').call(markerPath, 'qaItem-fill');
65603 markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
65604 var picon = d.icon;
65609 var isMaki = /^maki-/.test(picon);
65610 return "#".concat(picon).concat(isMaki ? '-11' : '');
65614 markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
65615 return d.id === selectedID;
65616 }).attr('transform', getTransform); // Draw targets..
65618 if (touchLayer.empty()) return;
65619 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
65620 var targets = touchLayer.selectAll('.qaItem.improveOSM').data(data, function (d) {
65624 targets.exit().remove(); // enter/update
65626 targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
65627 return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
65628 }).attr('transform', getTransform);
65630 function sortY(a, b) {
65631 return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
65633 } // Draw the ImproveOSM layer and schedule loading issues and updating markers.
65636 function drawImproveOSM(selection) {
65637 var service = getService();
65638 var surface = context.surface();
65640 if (surface && !surface.empty()) {
65641 touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
65644 drawLayer = selection.selectAll('.layer-improveOSM').data(service ? [0] : []);
65645 drawLayer.exit().remove();
65646 drawLayer = drawLayer.enter().append('g').attr('class', 'layer-improveOSM').style('display', _layerEnabled$1 ? 'block' : 'none').merge(drawLayer);
65648 if (_layerEnabled$1) {
65649 if (service && ~~context.map().zoom() >= minZoom) {
65651 service.loadIssues(projection);
65657 } // Toggles the layer on and off
65660 drawImproveOSM.enabled = function (val) {
65661 if (!arguments.length) return _layerEnabled$1;
65662 _layerEnabled$1 = val;
65664 if (_layerEnabled$1) {
65669 if (context.selectedErrorID()) {
65670 context.enter(modeBrowse(context));
65674 dispatch.call('change');
65678 drawImproveOSM.supported = function () {
65679 return !!getService();
65682 return drawImproveOSM;
65685 var _layerEnabled = false;
65689 function svgOsmose(projection, context, dispatch) {
65690 var throttledRedraw = throttle(function () {
65691 return dispatch.call('change');
65695 var touchLayer = select(null);
65696 var drawLayer = select(null);
65697 var layerVisible = false;
65699 function markerPath(selection, klass) {
65700 selection.attr('class', klass).attr('transform', 'translate(-10, -28)').attr('points', '16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6');
65701 } // Loosely-coupled osmose service for fetching issues
65704 function getService() {
65705 if (services.osmose && !_qaService) {
65706 _qaService = services.osmose;
65708 _qaService.on('loaded', throttledRedraw);
65709 } else if (!services.osmose && _qaService) {
65714 } // Show the markers
65717 function editOn() {
65718 if (!layerVisible) {
65719 layerVisible = true;
65720 drawLayer.style('display', 'block');
65722 } // Immediately remove the markers and their touch targets
65725 function editOff() {
65726 if (layerVisible) {
65727 layerVisible = false;
65728 drawLayer.style('display', 'none');
65729 drawLayer.selectAll('.qaItem.osmose').remove();
65730 touchLayer.selectAll('.qaItem.osmose').remove();
65732 } // Enable the layer. This shows the markers and transitions them to visible.
65735 function layerOn() {
65737 drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
65738 return dispatch.call('change');
65740 } // Disable the layer. This transitions the layer invisible and then hides the markers.
65743 function layerOff() {
65744 throttledRedraw.cancel();
65745 drawLayer.interrupt();
65746 touchLayer.selectAll('.qaItem.osmose').remove();
65747 drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
65749 dispatch.call('change');
65751 } // Update the issue markers
65754 function updateMarkers() {
65755 if (!layerVisible || !_layerEnabled) return;
65756 var service = getService();
65757 var selectedID = context.selectedErrorID();
65758 var data = service ? service.getItems(projection) : [];
65759 var getTransform = svgPointTransform(projection); // Draw markers..
65761 var markers = drawLayer.selectAll('.qaItem.osmose').data(data, function (d) {
65765 markers.exit().remove(); // enter
65767 var markersEnter = markers.enter().append('g').attr('class', function (d) {
65768 return "qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
65770 markersEnter.append('polygon').call(markerPath, 'shadow');
65771 markersEnter.append('ellipse').attr('cx', 0).attr('cy', 0).attr('rx', 4.5).attr('ry', 2).attr('class', 'stroke');
65772 markersEnter.append('polygon').attr('fill', function (d) {
65773 return service.getColor(d.item);
65774 }).call(markerPath, 'qaItem-fill');
65775 markersEnter.append('use').attr('transform', 'translate(-6.5, -23)').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('xlink:href', function (d) {
65776 var picon = d.icon;
65781 var isMaki = /^maki-/.test(picon);
65782 return "#".concat(picon).concat(isMaki ? '-11' : '');
65786 markers.merge(markersEnter).sort(sortY).classed('selected', function (d) {
65787 return d.id === selectedID;
65788 }).attr('transform', getTransform); // Draw targets..
65790 if (touchLayer.empty()) return;
65791 var fillClass = context.getDebug('target') ? 'pink' : 'nocolor';
65792 var targets = touchLayer.selectAll('.qaItem.osmose').data(data, function (d) {
65796 targets.exit().remove(); // enter/update
65798 targets.enter().append('rect').attr('width', '20px').attr('height', '30px').attr('x', '-10px').attr('y', '-28px').merge(targets).sort(sortY).attr('class', function (d) {
65799 return "qaItem ".concat(d.service, " target ").concat(fillClass, " itemId-").concat(d.id);
65800 }).attr('transform', getTransform);
65802 function sortY(a, b) {
65803 return a.id === selectedID ? 1 : b.id === selectedID ? -1 : b.loc[1] - a.loc[1];
65805 } // Draw the Osmose layer and schedule loading issues and updating markers.
65808 function drawOsmose(selection) {
65809 var service = getService();
65810 var surface = context.surface();
65812 if (surface && !surface.empty()) {
65813 touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
65816 drawLayer = selection.selectAll('.layer-osmose').data(service ? [0] : []);
65817 drawLayer.exit().remove();
65818 drawLayer = drawLayer.enter().append('g').attr('class', 'layer-osmose').style('display', _layerEnabled ? 'block' : 'none').merge(drawLayer);
65820 if (_layerEnabled) {
65821 if (service && ~~context.map().zoom() >= minZoom) {
65823 service.loadIssues(projection);
65829 } // Toggles the layer on and off
65832 drawOsmose.enabled = function (val) {
65833 if (!arguments.length) return _layerEnabled;
65834 _layerEnabled = val;
65836 if (_layerEnabled) {
65837 // Strings supplied by Osmose fetched before showing layer for first time
65838 // NOTE: Currently no way to change locale in iD at runtime, would need to re-call this method if that's ever implemented
65839 // Also, If layer is toggled quickly multiple requests are sent
65840 getService().loadStrings().then(layerOn)["catch"](function (err) {
65841 console.log(err); // eslint-disable-line no-console
65846 if (context.selectedErrorID()) {
65847 context.enter(modeBrowse(context));
65851 dispatch.call('change');
65855 drawOsmose.supported = function () {
65856 return !!getService();
65862 function svgStreetside(projection, context, dispatch) {
65863 var throttledRedraw = throttle(function () {
65864 dispatch.call('change');
65868 var minMarkerZoom = 16;
65869 var minViewfieldZoom = 18;
65870 var layer = select(null);
65871 var _viewerYaw = 0;
65872 var _selectedSequence = null;
65881 if (svgStreetside.initialized) return; // run once
65883 svgStreetside.enabled = false;
65884 svgStreetside.initialized = true;
65891 function getService() {
65892 if (services.streetside && !_streetside) {
65893 _streetside = services.streetside;
65895 _streetside.event.on('viewerChanged.svgStreetside', viewerChanged).on('loadedImages.svgStreetside', throttledRedraw);
65896 } else if (!services.streetside && _streetside) {
65897 _streetside = null;
65900 return _streetside;
65907 function showLayer() {
65908 var service = getService();
65909 if (!service) return;
65911 layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
65912 dispatch.call('change');
65920 function hideLayer() {
65921 throttledRedraw.cancel();
65922 layer.transition().duration(250).style('opacity', 0).on('end', editOff);
65929 function editOn() {
65930 layer.style('display', 'block');
65937 function editOff() {
65938 layer.selectAll('.viewfield-group').remove();
65939 layer.style('display', 'none');
65942 * click() Handles 'bubble' point click event.
65946 function click(d3_event, d) {
65947 var service = getService();
65948 if (!service) return; // try to preserve the viewer rotation when staying on the same sequence
65950 if (d.sequenceKey !== _selectedSequence) {
65951 _viewerYaw = 0; // reset
65954 _selectedSequence = d.sequenceKey;
65955 service.ensureViewerLoaded(context).then(function () {
65956 service.selectImage(context, d.key).yaw(_viewerYaw).showViewer(context);
65958 context.map().centerEase(d.loc);
65965 function mouseover(d3_event, d) {
65966 var service = getService();
65967 if (service) service.setStyles(context, d);
65974 function mouseout() {
65975 var service = getService();
65976 if (service) service.setStyles(context, null);
65983 function transform(d) {
65984 var t = svgPointTransform(projection)(d);
65985 var rot = d.ca + _viewerYaw;
65988 t += ' rotate(' + Math.floor(rot) + ',0,0)';
65994 function viewerChanged() {
65995 var service = getService();
65996 if (!service) return;
65997 var viewer = service.viewer();
65998 if (!viewer) return; // update viewfield rotation
66000 _viewerYaw = viewer.getYaw(); // avoid updating if the map is currently transformed
66001 // e.g. during drags or easing.
66003 if (context.map().isTransformed()) return;
66004 layer.selectAll('.viewfield-group.currentView').attr('transform', transform);
66007 function filterBubbles(bubbles) {
66008 var fromDate = context.photos().fromDate();
66009 var toDate = context.photos().toDate();
66010 var usernames = context.photos().usernames();
66013 var fromTimestamp = new Date(fromDate).getTime();
66014 bubbles = bubbles.filter(function (bubble) {
66015 return new Date(bubble.captured_at).getTime() >= fromTimestamp;
66020 var toTimestamp = new Date(toDate).getTime();
66021 bubbles = bubbles.filter(function (bubble) {
66022 return new Date(bubble.captured_at).getTime() <= toTimestamp;
66027 bubbles = bubbles.filter(function (bubble) {
66028 return usernames.indexOf(bubble.captured_by) !== -1;
66035 function filterSequences(sequences) {
66036 var fromDate = context.photos().fromDate();
66037 var toDate = context.photos().toDate();
66038 var usernames = context.photos().usernames();
66041 var fromTimestamp = new Date(fromDate).getTime();
66042 sequences = sequences.filter(function (sequences) {
66043 return new Date(sequences.properties.captured_at).getTime() >= fromTimestamp;
66048 var toTimestamp = new Date(toDate).getTime();
66049 sequences = sequences.filter(function (sequences) {
66050 return new Date(sequences.properties.captured_at).getTime() <= toTimestamp;
66055 sequences = sequences.filter(function (sequences) {
66056 return usernames.indexOf(sequences.properties.captured_by) !== -1;
66067 function update() {
66068 var viewer = context.container().select('.photoviewer');
66069 var selected = viewer.empty() ? undefined : viewer.datum();
66070 var z = ~~context.map().zoom();
66071 var showMarkers = z >= minMarkerZoom;
66072 var showViewfields = z >= minViewfieldZoom;
66073 var service = getService();
66074 var sequences = [];
66077 if (context.photos().showsPanoramic()) {
66078 sequences = service ? service.sequences(projection) : [];
66079 bubbles = service && showMarkers ? service.bubbles(projection) : [];
66080 sequences = filterSequences(sequences);
66081 bubbles = filterBubbles(bubbles);
66084 var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
66085 return d.properties.key;
66088 traces.exit().remove(); // enter/update
66090 traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
66091 var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(bubbles, function (d) {
66092 // force reenter once bubbles are attached to a sequence
66093 return d.key + (d.sequenceKey ? 'v1' : 'v0');
66096 groups.exit().remove(); // enter
66098 var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
66099 groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66101 var markers = groups.merge(groupsEnter).sort(function (a, b) {
66102 return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1];
66103 }).attr('transform', transform).select('.viewfield-scale');
66104 markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66105 var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66106 viewfields.exit().remove(); // viewfields may or may not be drawn...
66107 // but if they are, draw below the circles
66109 viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
66111 function viewfieldPath() {
66112 var d = this.parentNode.__data__;
66115 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
66117 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
66123 * drawImages is the method that is returned (and that runs) every time 'svgStreetside()' is called.
66124 * 'svgStreetside()' is called from index.js
66128 function drawImages(selection) {
66129 var enabled = svgStreetside.enabled;
66130 var service = getService();
66131 layer = selection.selectAll('.layer-streetside-images').data(service ? [0] : []);
66132 layer.exit().remove();
66133 var layerEnter = layer.enter().append('g').attr('class', 'layer-streetside-images').style('display', enabled ? 'block' : 'none');
66134 layerEnter.append('g').attr('class', 'sequences');
66135 layerEnter.append('g').attr('class', 'markers');
66136 layer = layerEnter.merge(layer);
66139 if (service && ~~context.map().zoom() >= minZoom) {
66142 service.loadBubbles(projection);
66149 * drawImages.enabled().
66153 drawImages.enabled = function (_) {
66154 if (!arguments.length) return svgStreetside.enabled;
66155 svgStreetside.enabled = _;
66157 if (svgStreetside.enabled) {
66159 context.photos().on('change.streetside', update);
66162 context.photos().on('change.streetside', null);
66165 dispatch.call('change');
66169 * drawImages.supported().
66173 drawImages.supported = function () {
66174 return !!getService();
66181 function svgMapillaryImages(projection, context, dispatch) {
66182 var throttledRedraw = throttle(function () {
66183 dispatch.call('change');
66187 var minMarkerZoom = 16;
66188 var minViewfieldZoom = 18;
66189 var layer = select(null);
66194 if (svgMapillaryImages.initialized) return; // run once
66196 svgMapillaryImages.enabled = false;
66197 svgMapillaryImages.initialized = true;
66200 function getService() {
66201 if (services.mapillary && !_mapillary) {
66202 _mapillary = services.mapillary;
66204 _mapillary.event.on('loadedImages', throttledRedraw);
66205 } else if (!services.mapillary && _mapillary) {
66212 function showLayer() {
66213 var service = getService();
66214 if (!service) return;
66216 layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
66217 dispatch.call('change');
66221 function hideLayer() {
66222 throttledRedraw.cancel();
66223 layer.transition().duration(250).style('opacity', 0).on('end', editOff);
66226 function editOn() {
66227 layer.style('display', 'block');
66230 function editOff() {
66231 layer.selectAll('.viewfield-group').remove();
66232 layer.style('display', 'none');
66235 function click(d3_event, image) {
66236 var service = getService();
66237 if (!service) return;
66238 service.ensureViewerLoaded(context).then(function () {
66239 service.selectImage(context, image.id).showViewer(context);
66241 context.map().centerEase(image.loc);
66244 function mouseover(d3_event, image) {
66245 var service = getService();
66246 if (service) service.setStyles(context, image);
66249 function mouseout() {
66250 var service = getService();
66251 if (service) service.setStyles(context, null);
66254 function transform(d) {
66255 var t = svgPointTransform(projection)(d);
66258 t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66264 function filterImages(images) {
66265 var showsPano = context.photos().showsPanoramic();
66266 var showsFlat = context.photos().showsFlat();
66267 var fromDate = context.photos().fromDate();
66268 var toDate = context.photos().toDate();
66270 if (!showsPano || !showsFlat) {
66271 images = images.filter(function (image) {
66272 if (image.is_pano) return showsPano;
66278 images = images.filter(function (image) {
66279 return new Date(image.captured_at).getTime() >= new Date(fromDate).getTime();
66284 images = images.filter(function (image) {
66285 return new Date(image.captured_at).getTime() <= new Date(toDate).getTime();
66292 function filterSequences(sequences) {
66293 var showsPano = context.photos().showsPanoramic();
66294 var showsFlat = context.photos().showsFlat();
66295 var fromDate = context.photos().fromDate();
66296 var toDate = context.photos().toDate();
66298 if (!showsPano || !showsFlat) {
66299 sequences = sequences.filter(function (sequence) {
66300 if (sequence.properties.hasOwnProperty('is_pano')) {
66301 if (sequence.properties.is_pano) return showsPano;
66310 sequences = sequences.filter(function (sequence) {
66311 return new Date(sequence.properties.captured_at).getTime() >= new Date(fromDate).getTime().toString();
66316 sequences = sequences.filter(function (sequence) {
66317 return new Date(sequence.properties.captured_at).getTime() <= new Date(toDate).getTime().toString();
66324 function update() {
66325 var z = ~~context.map().zoom();
66326 var showMarkers = z >= minMarkerZoom;
66327 var showViewfields = z >= minViewfieldZoom;
66328 var service = getService();
66329 var sequences = service ? service.sequences(projection) : [];
66330 var images = service && showMarkers ? service.images(projection) : [];
66331 images = filterImages(images);
66332 sequences = filterSequences(sequences);
66333 service.filterViewer(context);
66334 var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
66335 return d.properties.id;
66338 traces.exit().remove(); // enter/update
66340 traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
66341 var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
66345 groups.exit().remove(); // enter
66347 var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
66348 groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66350 var markers = groups.merge(groupsEnter).sort(function (a, b) {
66351 return b.loc[1] - a.loc[1]; // sort Y
66352 }).attr('transform', transform).select('.viewfield-scale');
66353 markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66354 var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66355 viewfields.exit().remove();
66356 viewfields.enter() // viewfields may or may not be drawn...
66357 .insert('path', 'circle') // but if they are, draw below the circles
66358 .attr('class', 'viewfield').classed('pano', function () {
66359 return this.parentNode.__data__.is_pano;
66360 }).attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', viewfieldPath);
66362 function viewfieldPath() {
66363 if (this.parentNode.__data__.is_pano) {
66364 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
66366 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
66371 function drawImages(selection) {
66372 var enabled = svgMapillaryImages.enabled;
66373 var service = getService();
66374 layer = selection.selectAll('.layer-mapillary').data(service ? [0] : []);
66375 layer.exit().remove();
66376 var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary').style('display', enabled ? 'block' : 'none');
66377 layerEnter.append('g').attr('class', 'sequences');
66378 layerEnter.append('g').attr('class', 'markers');
66379 layer = layerEnter.merge(layer);
66382 if (service && ~~context.map().zoom() >= minZoom) {
66385 service.loadImages(projection);
66392 drawImages.enabled = function (_) {
66393 if (!arguments.length) return svgMapillaryImages.enabled;
66394 svgMapillaryImages.enabled = _;
66396 if (svgMapillaryImages.enabled) {
66398 context.photos().on('change.mapillary_images', update);
66401 context.photos().on('change.mapillary_images', null);
66404 dispatch.call('change');
66408 drawImages.supported = function () {
66409 return !!getService();
66416 function svgMapillaryPosition(projection, context) {
66417 var throttledRedraw = throttle(function () {
66422 var minViewfieldZoom = 18;
66423 var layer = select(null);
66427 var viewerCompassAngle;
66430 if (svgMapillaryPosition.initialized) return; // run once
66432 svgMapillaryPosition.initialized = true;
66435 function getService() {
66436 if (services.mapillary && !_mapillary) {
66437 _mapillary = services.mapillary;
66439 _mapillary.event.on('imageChanged', throttledRedraw);
66441 _mapillary.event.on('bearingChanged', function (e) {
66442 viewerCompassAngle = e.bearing;
66443 if (context.map().isTransformed()) return;
66444 layer.selectAll('.viewfield-group.currentView').filter(function (d) {
66446 }).attr('transform', transform);
66448 } else if (!services.mapillary && _mapillary) {
66455 function editOn() {
66456 layer.style('display', 'block');
66459 function editOff() {
66460 layer.selectAll('.viewfield-group').remove();
66461 layer.style('display', 'none');
66464 function transform(d) {
66465 var t = svgPointTransform(projection)(d);
66467 if (d.is_pano && viewerCompassAngle !== null && isFinite(viewerCompassAngle)) {
66468 t += ' rotate(' + Math.floor(viewerCompassAngle) + ',0,0)';
66470 t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66476 function update() {
66477 var z = ~~context.map().zoom();
66478 var showViewfields = z >= minViewfieldZoom;
66479 var service = getService();
66480 var image = service && service.getActiveImage();
66481 var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(image ? [image] : [], function (d) {
66485 groups.exit().remove(); // enter
66487 var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group currentView highlighted');
66488 groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
66490 var markers = groups.merge(groupsEnter).attr('transform', transform).select('.viewfield-scale');
66491 markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
66492 var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
66493 viewfields.exit().remove();
66494 viewfields.enter().insert('path', 'circle').attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z');
66497 function drawImages(selection) {
66498 var service = getService();
66499 layer = selection.selectAll('.layer-mapillary-position').data(service ? [0] : []);
66500 layer.exit().remove();
66501 var layerEnter = layer.enter().append('g').attr('class', 'layer-mapillary-position');
66502 layerEnter.append('g').attr('class', 'markers');
66503 layer = layerEnter.merge(layer);
66505 if (service && ~~context.map().zoom() >= minZoom) {
66513 drawImages.enabled = function () {
66518 drawImages.supported = function () {
66519 return !!getService();
66526 function svgMapillarySigns(projection, context, dispatch) {
66527 var throttledRedraw = throttle(function () {
66528 dispatch.call('change');
66532 var layer = select(null);
66537 if (svgMapillarySigns.initialized) return; // run once
66539 svgMapillarySigns.enabled = false;
66540 svgMapillarySigns.initialized = true;
66543 function getService() {
66544 if (services.mapillary && !_mapillary) {
66545 _mapillary = services.mapillary;
66547 _mapillary.event.on('loadedSigns', throttledRedraw);
66548 } else if (!services.mapillary && _mapillary) {
66555 function showLayer() {
66556 var service = getService();
66557 if (!service) return;
66558 service.loadSignResources(context);
66562 function hideLayer() {
66563 throttledRedraw.cancel();
66567 function editOn() {
66568 layer.style('display', 'block');
66571 function editOff() {
66572 layer.selectAll('.icon-sign').remove();
66573 layer.style('display', 'none');
66576 function click(d3_event, d) {
66577 var service = getService();
66578 if (!service) return;
66579 context.map().centerEase(d.loc);
66580 var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
66581 service.getDetections(d.id).then(function (detections) {
66582 if (detections.length) {
66583 var imageId = detections[0].image.id;
66585 if (imageId === selectedImageId) {
66586 service.highlightDetection(detections[0]).selectImage(context, imageId);
66588 service.ensureViewerLoaded(context).then(function () {
66589 service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
66596 function filterData(detectedFeatures) {
66597 var fromDate = context.photos().fromDate();
66598 var toDate = context.photos().toDate();
66601 var fromTimestamp = new Date(fromDate).getTime();
66602 detectedFeatures = detectedFeatures.filter(function (feature) {
66603 return new Date(feature.last_seen_at).getTime() >= fromTimestamp;
66608 var toTimestamp = new Date(toDate).getTime();
66609 detectedFeatures = detectedFeatures.filter(function (feature) {
66610 return new Date(feature.first_seen_at).getTime() <= toTimestamp;
66614 return detectedFeatures;
66617 function update() {
66618 var service = getService();
66619 var data = service ? service.signs(projection) : [];
66620 data = filterData(data);
66621 var transform = svgPointTransform(projection);
66622 var signs = layer.selectAll('.icon-sign').data(data, function (d) {
66626 signs.exit().remove(); // enter
66628 var enter = signs.enter().append('g').attr('class', 'icon-sign icon-detected').on('click', click);
66629 enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
66630 return '#' + d.value;
66632 enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
66634 signs.merge(enter).attr('transform', transform);
66637 function drawSigns(selection) {
66638 var enabled = svgMapillarySigns.enabled;
66639 var service = getService();
66640 layer = selection.selectAll('.layer-mapillary-signs').data(service ? [0] : []);
66641 layer.exit().remove();
66642 layer = layer.enter().append('g').attr('class', 'layer-mapillary-signs layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
66645 if (service && ~~context.map().zoom() >= minZoom) {
66648 service.loadSigns(projection);
66649 service.showSignDetections(true);
66653 } else if (service) {
66654 service.showSignDetections(false);
66658 drawSigns.enabled = function (_) {
66659 if (!arguments.length) return svgMapillarySigns.enabled;
66660 svgMapillarySigns.enabled = _;
66662 if (svgMapillarySigns.enabled) {
66664 context.photos().on('change.mapillary_signs', update);
66667 context.photos().on('change.mapillary_signs', null);
66670 dispatch.call('change');
66674 drawSigns.supported = function () {
66675 return !!getService();
66682 function svgMapillaryMapFeatures(projection, context, dispatch) {
66683 var throttledRedraw = throttle(function () {
66684 dispatch.call('change');
66688 var layer = select(null);
66693 if (svgMapillaryMapFeatures.initialized) return; // run once
66695 svgMapillaryMapFeatures.enabled = false;
66696 svgMapillaryMapFeatures.initialized = true;
66699 function getService() {
66700 if (services.mapillary && !_mapillary) {
66701 _mapillary = services.mapillary;
66703 _mapillary.event.on('loadedMapFeatures', throttledRedraw);
66704 } else if (!services.mapillary && _mapillary) {
66711 function showLayer() {
66712 var service = getService();
66713 if (!service) return;
66714 service.loadObjectResources(context);
66718 function hideLayer() {
66719 throttledRedraw.cancel();
66723 function editOn() {
66724 layer.style('display', 'block');
66727 function editOff() {
66728 layer.selectAll('.icon-map-feature').remove();
66729 layer.style('display', 'none');
66732 function click(d3_event, d) {
66733 var service = getService();
66734 if (!service) return;
66735 context.map().centerEase(d.loc);
66736 var selectedImageId = service.getActiveImage() && service.getActiveImage().id;
66737 service.getDetections(d.id).then(function (detections) {
66738 if (detections.length) {
66739 var imageId = detections[0].image.id;
66741 if (imageId === selectedImageId) {
66742 service.highlightDetection(detections[0]).selectImage(context, imageId);
66744 service.ensureViewerLoaded(context).then(function () {
66745 service.highlightDetection(detections[0]).selectImage(context, imageId).showViewer(context);
66752 function filterData(detectedFeatures) {
66753 var fromDate = context.photos().fromDate();
66754 var toDate = context.photos().toDate();
66757 detectedFeatures = detectedFeatures.filter(function (feature) {
66758 return new Date(feature.last_seen_at).getTime() >= new Date(fromDate).getTime();
66763 detectedFeatures = detectedFeatures.filter(function (feature) {
66764 return new Date(feature.first_seen_at).getTime() <= new Date(toDate).getTime();
66768 return detectedFeatures;
66771 function update() {
66772 var service = getService();
66773 var data = service ? service.mapFeatures(projection) : [];
66774 data = filterData(data);
66775 var transform = svgPointTransform(projection);
66776 var mapFeatures = layer.selectAll('.icon-map-feature').data(data, function (d) {
66780 mapFeatures.exit().remove(); // enter
66782 var enter = mapFeatures.enter().append('g').attr('class', 'icon-map-feature icon-detected').on('click', click);
66783 enter.append('title').text(function (d) {
66784 var id = d.value.replace(/--/g, '.').replace(/-/g, '_');
66785 return _t('mapillary_map_features.' + id);
66787 enter.append('use').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px').attr('xlink:href', function (d) {
66788 if (d.value === 'object--billboard') {
66789 // no billboard icon right now, so use the advertisement icon
66790 return '#object--sign--advertisement';
66793 return '#' + d.value;
66795 enter.append('rect').attr('width', '24px').attr('height', '24px').attr('x', '-12px').attr('y', '-12px'); // update
66797 mapFeatures.merge(enter).attr('transform', transform);
66800 function drawMapFeatures(selection) {
66801 var enabled = svgMapillaryMapFeatures.enabled;
66802 var service = getService();
66803 layer = selection.selectAll('.layer-mapillary-map-features').data(service ? [0] : []);
66804 layer.exit().remove();
66805 layer = layer.enter().append('g').attr('class', 'layer-mapillary-map-features layer-mapillary-detections').style('display', enabled ? 'block' : 'none').merge(layer);
66808 if (service && ~~context.map().zoom() >= minZoom) {
66811 service.loadMapFeatures(projection);
66812 service.showFeatureDetections(true);
66816 } else if (service) {
66817 service.showFeatureDetections(false);
66821 drawMapFeatures.enabled = function (_) {
66822 if (!arguments.length) return svgMapillaryMapFeatures.enabled;
66823 svgMapillaryMapFeatures.enabled = _;
66825 if (svgMapillaryMapFeatures.enabled) {
66827 context.photos().on('change.mapillary_map_features', update);
66830 context.photos().on('change.mapillary_map_features', null);
66833 dispatch.call('change');
66837 drawMapFeatures.supported = function () {
66838 return !!getService();
66842 return drawMapFeatures;
66845 function svgOpenstreetcamImages(projection, context, dispatch) {
66846 var throttledRedraw = throttle(function () {
66847 dispatch.call('change');
66851 var minMarkerZoom = 16;
66852 var minViewfieldZoom = 18;
66853 var layer = select(null);
66855 var _openstreetcam;
66858 if (svgOpenstreetcamImages.initialized) return; // run once
66860 svgOpenstreetcamImages.enabled = false;
66861 svgOpenstreetcamImages.initialized = true;
66864 function getService() {
66865 if (services.openstreetcam && !_openstreetcam) {
66866 _openstreetcam = services.openstreetcam;
66868 _openstreetcam.event.on('loadedImages', throttledRedraw);
66869 } else if (!services.openstreetcam && _openstreetcam) {
66870 _openstreetcam = null;
66873 return _openstreetcam;
66876 function showLayer() {
66877 var service = getService();
66878 if (!service) return;
66880 layer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end', function () {
66881 dispatch.call('change');
66885 function hideLayer() {
66886 throttledRedraw.cancel();
66887 layer.transition().duration(250).style('opacity', 0).on('end', editOff);
66890 function editOn() {
66891 layer.style('display', 'block');
66894 function editOff() {
66895 layer.selectAll('.viewfield-group').remove();
66896 layer.style('display', 'none');
66899 function click(d3_event, d) {
66900 var service = getService();
66901 if (!service) return;
66902 service.ensureViewerLoaded(context).then(function () {
66903 service.selectImage(context, d.key).showViewer(context);
66905 context.map().centerEase(d.loc);
66908 function mouseover(d3_event, d) {
66909 var service = getService();
66910 if (service) service.setStyles(context, d);
66913 function mouseout() {
66914 var service = getService();
66915 if (service) service.setStyles(context, null);
66918 function transform(d) {
66919 var t = svgPointTransform(projection)(d);
66922 t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
66928 function filterImages(images) {
66929 var fromDate = context.photos().fromDate();
66930 var toDate = context.photos().toDate();
66931 var usernames = context.photos().usernames();
66934 var fromTimestamp = new Date(fromDate).getTime();
66935 images = images.filter(function (item) {
66936 return new Date(item.captured_at).getTime() >= fromTimestamp;
66941 var toTimestamp = new Date(toDate).getTime();
66942 images = images.filter(function (item) {
66943 return new Date(item.captured_at).getTime() <= toTimestamp;
66948 images = images.filter(function (item) {
66949 return usernames.indexOf(item.captured_by) !== -1;
66956 function filterSequences(sequences) {
66957 var fromDate = context.photos().fromDate();
66958 var toDate = context.photos().toDate();
66959 var usernames = context.photos().usernames();
66962 var fromTimestamp = new Date(fromDate).getTime();
66963 sequences = sequences.filter(function (image) {
66964 return new Date(image.properties.captured_at).getTime() >= fromTimestamp;
66969 var toTimestamp = new Date(toDate).getTime();
66970 sequences = sequences.filter(function (image) {
66971 return new Date(image.properties.captured_at).getTime() <= toTimestamp;
66976 sequences = sequences.filter(function (image) {
66977 return usernames.indexOf(image.properties.captured_by) !== -1;
66984 function update() {
66985 var viewer = context.container().select('.photoviewer');
66986 var selected = viewer.empty() ? undefined : viewer.datum();
66987 var z = ~~context.map().zoom();
66988 var showMarkers = z >= minMarkerZoom;
66989 var showViewfields = z >= minViewfieldZoom;
66990 var service = getService();
66991 var sequences = [];
66994 if (context.photos().showsFlat()) {
66995 sequences = service ? service.sequences(projection) : [];
66996 images = service && showMarkers ? service.images(projection) : [];
66997 sequences = filterSequences(sequences);
66998 images = filterImages(images);
67001 var traces = layer.selectAll('.sequences').selectAll('.sequence').data(sequences, function (d) {
67002 return d.properties.key;
67005 traces.exit().remove(); // enter/update
67007 traces = traces.enter().append('path').attr('class', 'sequence').merge(traces).attr('d', svgPath(projection).geojson);
67008 var groups = layer.selectAll('.markers').selectAll('.viewfield-group').data(images, function (d) {
67012 groups.exit().remove(); // enter
67014 var groupsEnter = groups.enter().append('g').attr('class', 'viewfield-group').on('mouseenter', mouseover).on('mouseleave', mouseout).on('click', click);
67015 groupsEnter.append('g').attr('class', 'viewfield-scale'); // update
67017 var markers = groups.merge(groupsEnter).sort(function (a, b) {
67018 return a === selected ? 1 : b === selected ? -1 : b.loc[1] - a.loc[1]; // sort Y
67019 }).attr('transform', transform).select('.viewfield-scale');
67020 markers.selectAll('circle').data([0]).enter().append('circle').attr('dx', '0').attr('dy', '0').attr('r', '6');
67021 var viewfields = markers.selectAll('.viewfield').data(showViewfields ? [0] : []);
67022 viewfields.exit().remove();
67023 viewfields.enter() // viewfields may or may not be drawn...
67024 .insert('path', 'circle') // but if they are, draw below the circles
67025 .attr('class', 'viewfield').attr('transform', 'scale(1.5,1.5),translate(-8, -13)').attr('d', 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z');
67028 function drawImages(selection) {
67029 var enabled = svgOpenstreetcamImages.enabled,
67030 service = getService();
67031 layer = selection.selectAll('.layer-openstreetcam').data(service ? [0] : []);
67032 layer.exit().remove();
67033 var layerEnter = layer.enter().append('g').attr('class', 'layer-openstreetcam').style('display', enabled ? 'block' : 'none');
67034 layerEnter.append('g').attr('class', 'sequences');
67035 layerEnter.append('g').attr('class', 'markers');
67036 layer = layerEnter.merge(layer);
67039 if (service && ~~context.map().zoom() >= minZoom) {
67042 service.loadImages(projection);
67049 drawImages.enabled = function (_) {
67050 if (!arguments.length) return svgOpenstreetcamImages.enabled;
67051 svgOpenstreetcamImages.enabled = _;
67053 if (svgOpenstreetcamImages.enabled) {
67055 context.photos().on('change.openstreetcam_images', update);
67058 context.photos().on('change.openstreetcam_images', null);
67061 dispatch.call('change');
67065 drawImages.supported = function () {
67066 return !!getService();
67073 function svgOsm(projection, context, dispatch) {
67074 var enabled = true;
67076 function drawOsm(selection) {
67077 selection.selectAll('.layer-osm').data(['covered', 'areas', 'lines', 'points', 'labels']).enter().append('g').attr('class', function (d) {
67078 return 'layer-osm ' + d;
67080 selection.selectAll('.layer-osm.points').selectAll('.points-group').data(['points', 'midpoints', 'vertices', 'turns']).enter().append('g').attr('class', function (d) {
67081 return 'points-group ' + d;
67085 function showLayer() {
67086 var layer = context.surface().selectAll('.data-layer.osm');
67088 layer.classed('disabled', false).style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
67089 dispatch.call('change');
67093 function hideLayer() {
67094 var layer = context.surface().selectAll('.data-layer.osm');
67096 layer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
67097 layer.classed('disabled', true);
67098 dispatch.call('change');
67102 drawOsm.enabled = function (val) {
67103 if (!arguments.length) return enabled;
67112 dispatch.call('change');
67119 var _notesEnabled = false;
67123 function svgNotes(projection, context, dispatch) {
67125 dispatch = dispatch$8('change');
67128 var throttledRedraw = throttle(function () {
67129 dispatch.call('change');
67133 var touchLayer = select(null);
67134 var drawLayer = select(null);
67135 var _notesVisible = false;
67137 function markerPath(selection, klass) {
67138 selection.attr('class', klass).attr('transform', 'translate(-8, -22)').attr('d', 'm17.5,0l-15,0c-1.37,0 -2.5,1.12 -2.5,2.5l0,11.25c0,1.37 1.12,2.5 2.5,2.5l3.75,0l0,3.28c0,0.38 0.43,0.6 0.75,0.37l4.87,-3.65l5.62,0c1.37,0 2.5,-1.12 2.5,-2.5l0,-11.25c0,-1.37 -1.12,-2.5 -2.5,-2.5z');
67139 } // Loosely-coupled osm service for fetching notes.
67142 function getService() {
67143 if (services.osm && !_osmService) {
67144 _osmService = services.osm;
67146 _osmService.on('loadedNotes', throttledRedraw);
67147 } else if (!services.osm && _osmService) {
67148 _osmService = null;
67151 return _osmService;
67152 } // Show the notes
67155 function editOn() {
67156 if (!_notesVisible) {
67157 _notesVisible = true;
67158 drawLayer.style('display', 'block');
67160 } // Immediately remove the notes and their touch targets
67163 function editOff() {
67164 if (_notesVisible) {
67165 _notesVisible = false;
67166 drawLayer.style('display', 'none');
67167 drawLayer.selectAll('.note').remove();
67168 touchLayer.selectAll('.note').remove();
67170 } // Enable the layer. This shows the notes and transitions them to visible.
67173 function layerOn() {
67175 drawLayer.style('opacity', 0).transition().duration(250).style('opacity', 1).on('end interrupt', function () {
67176 dispatch.call('change');
67178 } // Disable the layer. This transitions the layer invisible and then hides the notes.
67181 function layerOff() {
67182 throttledRedraw.cancel();
67183 drawLayer.interrupt();
67184 touchLayer.selectAll('.note').remove();
67185 drawLayer.transition().duration(250).style('opacity', 0).on('end interrupt', function () {
67187 dispatch.call('change');
67189 } // Update the note markers
67192 function updateMarkers() {
67193 if (!_notesVisible || !_notesEnabled) return;
67194 var service = getService();
67195 var selectedID = context.selectedNoteID();
67196 var data = service ? service.notes(projection) : [];
67197 var getTransform = svgPointTransform(projection); // Draw markers..
67199 var notes = drawLayer.selectAll('.note').data(data, function (d) {
67200 return d.status + d.id;
67203 notes.exit().remove(); // enter
67205 var notesEnter = notes.enter().append('g').attr('class', function (d) {
67206 return 'note note-' + d.id + ' ' + d.status;
67207 }).classed('new', function (d) {
67210 notesEnter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
67211 notesEnter.append('path').call(markerPath, 'shadow');
67212 notesEnter.append('use').attr('class', 'note-fill').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').attr('xlink:href', '#iD-icon-note');
67213 notesEnter.selectAll('.icon-annotation').data(function (d) {
67215 }).enter().append('use').attr('class', 'icon-annotation').attr('width', '10px').attr('height', '10px').attr('x', '-3px').attr('y', '-19px').attr('xlink:href', function (d) {
67216 if (d.id < 0) return '#iD-icon-plus';
67217 if (d.status === 'open') return '#iD-icon-close';
67218 return '#iD-icon-apply';
67221 notes.merge(notesEnter).sort(sortY).classed('selected', function (d) {
67222 var mode = context.mode();
67223 var isMoving = mode && mode.id === 'drag-note'; // no shadows when dragging
67225 return !isMoving && d.id === selectedID;
67226 }).attr('transform', getTransform); // Draw targets..
67228 if (touchLayer.empty()) return;
67229 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67230 var targets = touchLayer.selectAll('.note').data(data, function (d) {
67234 targets.exit().remove(); // enter/update
67236 targets.enter().append('rect').attr('width', '20px').attr('height', '20px').attr('x', '-8px').attr('y', '-22px').merge(targets).sort(sortY).attr('class', function (d) {
67237 var newClass = d.id < 0 ? 'new' : '';
67238 return 'note target note-' + d.id + ' ' + fillClass + newClass;
67239 }).attr('transform', getTransform);
67241 function sortY(a, b) {
67242 if (a.id === selectedID) return 1;
67243 if (b.id === selectedID) return -1;
67244 return b.loc[1] - a.loc[1];
67246 } // Draw the notes layer and schedule loading notes and updating markers.
67249 function drawNotes(selection) {
67250 var service = getService();
67251 var surface = context.surface();
67253 if (surface && !surface.empty()) {
67254 touchLayer = surface.selectAll('.data-layer.touch .layer-touch.markers');
67257 drawLayer = selection.selectAll('.layer-notes').data(service ? [0] : []);
67258 drawLayer.exit().remove();
67259 drawLayer = drawLayer.enter().append('g').attr('class', 'layer-notes').style('display', _notesEnabled ? 'block' : 'none').merge(drawLayer);
67261 if (_notesEnabled) {
67262 if (service && ~~context.map().zoom() >= minZoom) {
67264 service.loadNotes(projection);
67270 } // Toggles the layer on and off
67273 drawNotes.enabled = function (val) {
67274 if (!arguments.length) return _notesEnabled;
67275 _notesEnabled = val;
67277 if (_notesEnabled) {
67282 if (context.selectedNoteID()) {
67283 context.enter(modeBrowse(context));
67287 dispatch.call('change');
67294 function svgTouch() {
67295 function drawTouch(selection) {
67296 selection.selectAll('.layer-touch').data(['areas', 'lines', 'points', 'turns', 'markers']).enter().append('g').attr('class', function (d) {
67297 return 'layer-touch ' + d;
67304 function refresh(selection, node) {
67305 var cr = node.getBoundingClientRect();
67306 var prop = [cr.width, cr.height];
67307 selection.property('__dimensions__', prop);
67311 function utilGetDimensions(selection, force) {
67312 if (!selection || selection.empty()) {
67316 var node = selection.node(),
67317 cached = selection.property('__dimensions__');
67318 return !cached || force ? refresh(selection, node) : cached;
67320 function utilSetDimensions(selection, dimensions) {
67321 if (!selection || selection.empty()) {
67325 var node = selection.node();
67327 if (dimensions === null) {
67328 refresh(selection, node);
67332 return selection.property('__dimensions__', [dimensions[0], dimensions[1]]).attr('width', dimensions[0]).attr('height', dimensions[1]);
67335 function svgLayers(projection, context) {
67336 var dispatch = dispatch$8('change');
67337 var svg = select(null);
67340 layer: svgOsm(projection, context, dispatch)
67343 layer: svgNotes(projection, context, dispatch)
67346 layer: svgData(projection, context, dispatch)
67349 layer: svgKeepRight(projection, context, dispatch)
67352 layer: svgImproveOSM(projection, context, dispatch)
67355 layer: svgOsmose(projection, context, dispatch)
67358 layer: svgStreetside(projection, context, dispatch)
67361 layer: svgMapillaryImages(projection, context, dispatch)
67363 id: 'mapillary-position',
67364 layer: svgMapillaryPosition(projection, context)
67366 id: 'mapillary-map-features',
67367 layer: svgMapillaryMapFeatures(projection, context, dispatch)
67369 id: 'mapillary-signs',
67370 layer: svgMapillarySigns(projection, context, dispatch)
67372 id: 'openstreetcam',
67373 layer: svgOpenstreetcamImages(projection, context, dispatch)
67376 layer: svgDebug(projection, context)
67379 layer: svgGeolocate(projection)
67385 function drawLayers(selection) {
67386 svg = selection.selectAll('.surface').data([0]);
67387 svg = svg.enter().append('svg').attr('class', 'surface').merge(svg);
67388 var defs = svg.selectAll('.surface-defs').data([0]);
67389 defs.enter().append('defs').attr('class', 'surface-defs');
67390 var groups = svg.selectAll('.data-layer').data(_layers);
67391 groups.exit().remove();
67392 groups.enter().append('g').attr('class', function (d) {
67393 return 'data-layer ' + d.id;
67394 }).merge(groups).each(function (d) {
67395 select(this).call(d.layer);
67399 drawLayers.all = function () {
67403 drawLayers.layer = function (id) {
67404 var obj = _layers.find(function (o) {
67405 return o.id === id;
67408 return obj && obj.layer;
67411 drawLayers.only = function (what) {
67412 var arr = [].concat(what);
67414 var all = _layers.map(function (layer) {
67418 return drawLayers.remove(utilArrayDifference(all, arr));
67421 drawLayers.remove = function (what) {
67422 var arr = [].concat(what);
67423 arr.forEach(function (id) {
67424 _layers = _layers.filter(function (o) {
67425 return o.id !== id;
67428 dispatch.call('change');
67432 drawLayers.add = function (what) {
67433 var arr = [].concat(what);
67434 arr.forEach(function (obj) {
67435 if ('id' in obj && 'layer' in obj) {
67439 dispatch.call('change');
67443 drawLayers.dimensions = function (val) {
67444 if (!arguments.length) return utilGetDimensions(svg);
67445 utilSetDimensions(svg, val);
67449 return utilRebind(drawLayers, dispatch, 'on');
67452 function svgLines(projection, context) {
67453 var detected = utilDetect();
67454 var highway_stack = {
67469 function drawTargets(selection, graph, entities, filter) {
67470 var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67471 var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
67472 var getPath = svgPath(projection).geojson;
67473 var activeID = context.activeID();
67474 var base = context.history().base(); // The targets and nopes will be MultiLineString sub-segments of the ways
67480 entities.forEach(function (way) {
67481 var features = svgSegmentWay(way, graph, activeID);
67482 data.targets.push.apply(data.targets, features.passive);
67483 data.nopes.push.apply(data.nopes, features.active);
67484 }); // Targets allow hover and vertex snapping
67486 var targetData = data.targets.filter(getPath);
67487 var targets = selection.selectAll('.line.target-allowed').filter(function (d) {
67488 return filter(d.properties.entity);
67489 }).data(targetData, function key(d) {
67493 targets.exit().remove();
67495 var segmentWasEdited = function segmentWasEdited(d) {
67496 var wayID = d.properties.entity.id; // if the whole line was edited, don't draw segment changes
67498 if (!base.entities[wayID] || !fastDeepEqual(graph.entities[wayID].nodes, base.entities[wayID].nodes)) {
67502 return d.properties.nodes.some(function (n) {
67503 return !base.entities[n.id] || !fastDeepEqual(graph.entities[n.id].loc, base.entities[n.id].loc);
67508 targets.enter().append('path').merge(targets).attr('d', getPath).attr('class', function (d) {
67509 return 'way line target target-allowed ' + targetClass + d.id;
67510 }).classed('segment-edited', segmentWasEdited); // NOPE
67512 var nopeData = data.nopes.filter(getPath);
67513 var nopes = selection.selectAll('.line.target-nope').filter(function (d) {
67514 return filter(d.properties.entity);
67515 }).data(nopeData, function key(d) {
67519 nopes.exit().remove(); // enter/update
67521 nopes.enter().append('path').merge(nopes).attr('d', getPath).attr('class', function (d) {
67522 return 'way line target target-nope ' + nopeClass + d.id;
67523 }).classed('segment-edited', segmentWasEdited);
67526 function drawLines(selection, graph, entities, filter) {
67527 var base = context.history().base();
67529 function waystack(a, b) {
67530 var selected = context.selectedIDs();
67531 var scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0;
67532 var scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0;
67534 if (a.tags.highway) {
67535 scoreA -= highway_stack[a.tags.highway];
67538 if (b.tags.highway) {
67539 scoreB -= highway_stack[b.tags.highway];
67542 return scoreA - scoreB;
67545 function drawLineGroup(selection, klass, isSelected) {
67546 // Note: Don't add `.selected` class in draw modes
67547 var mode = context.mode();
67548 var isDrawing = mode && /^draw/.test(mode.id);
67549 var selectedClass = !isDrawing && isSelected ? 'selected ' : '';
67550 var lines = selection.selectAll('path').filter(filter).data(getPathData(isSelected), osmEntity.key);
67551 lines.exit().remove(); // Optimization: Call expensive TagClasses only on enter selection. This
67552 // works because osmEntity.key is defined to include the entity v attribute.
67554 lines.enter().append('path').attr('class', function (d) {
67555 var prefix = 'way line'; // if this line isn't styled by its own tags
67557 if (!d.hasInterestingTags()) {
67558 var parentRelations = graph.parentRelations(d);
67559 var parentMultipolygons = parentRelations.filter(function (relation) {
67560 return relation.isMultipolygon();
67561 }); // and if it's a member of at least one multipolygon relation
67563 if (parentMultipolygons.length > 0 && // and only multipolygon relations
67564 parentRelations.length === parentMultipolygons.length) {
67565 // then fudge the classes to style this as an area edge
67566 prefix = 'relation area';
67570 var oldMPClass = oldMultiPolygonOuters[d.id] ? 'old-multipolygon ' : '';
67571 return prefix + ' ' + klass + ' ' + selectedClass + oldMPClass + d.id;
67572 }).classed('added', function (d) {
67573 return !base.entities[d.id];
67574 }).classed('geometry-edited', function (d) {
67575 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].nodes, base.entities[d.id].nodes);
67576 }).classed('retagged', function (d) {
67577 return graph.entities[d.id] && base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67578 }).call(svgTagClasses()).merge(lines).sort(waystack).attr('d', getPath).call(svgTagClasses().tags(svgRelationMemberTags(graph)));
67582 function getPathData(isSelected) {
67583 return function () {
67584 var layer = this.parentNode.__data__;
67585 var data = pathdata[layer] || [];
67586 return data.filter(function (d) {
67588 return context.selectedIDs().indexOf(d.id) !== -1;
67590 return context.selectedIDs().indexOf(d.id) === -1;
67596 function addMarkers(layergroup, pathclass, groupclass, groupdata, marker) {
67597 var markergroup = layergroup.selectAll('g.' + groupclass).data([pathclass]);
67598 markergroup = markergroup.enter().append('g').attr('class', groupclass).merge(markergroup);
67599 var markers = markergroup.selectAll('path').filter(filter).data(function data() {
67600 return groupdata[this.parentNode.__data__] || [];
67601 }, function key(d) {
67602 return [d.id, d.index];
67604 markers.exit().remove();
67605 markers = markers.enter().append('path').attr('class', pathclass).merge(markers).attr('marker-mid', marker).attr('d', function (d) {
67610 markers.each(function () {
67611 this.parentNode.insertBefore(this, this);
67616 var getPath = svgPath(projection, graph);
67618 var onewaydata = {};
67619 var sideddata = {};
67620 var oldMultiPolygonOuters = {};
67622 for (var i = 0; i < entities.length; i++) {
67623 var entity = entities[i];
67624 var outer = osmOldMultipolygonOuterMember(entity, graph);
67627 ways.push(entity.mergeTags(outer.tags));
67628 oldMultiPolygonOuters[outer.id] = true;
67629 } else if (entity.geometry(graph) === 'line') {
67634 ways = ways.filter(getPath);
67635 var pathdata = utilArrayGroupBy(ways, function (way) {
67636 return way.layer();
67638 Object.keys(pathdata).forEach(function (k) {
67639 var v = pathdata[k];
67640 var onewayArr = v.filter(function (d) {
67641 return d.isOneWay();
67643 var onewaySegments = svgMarkerSegments(projection, graph, 35, function shouldReverse(entity) {
67644 return entity.tags.oneway === '-1';
67645 }, function bothDirections(entity) {
67646 return entity.tags.oneway === 'reversible' || entity.tags.oneway === 'alternating';
67648 onewaydata[k] = utilArrayFlatten(onewayArr.map(onewaySegments));
67649 var sidedArr = v.filter(function (d) {
67650 return d.isSided();
67652 var sidedSegments = svgMarkerSegments(projection, graph, 30, function shouldReverse() {
67654 }, function bothDirections() {
67657 sideddata[k] = utilArrayFlatten(sidedArr.map(sidedSegments));
67659 var covered = selection.selectAll('.layer-osm.covered'); // under areas
67661 var uncovered = selection.selectAll('.layer-osm.lines'); // over areas
67663 var touchLayer = selection.selectAll('.layer-touch.lines'); // Draw lines..
67665 [covered, uncovered].forEach(function (selection) {
67666 var range = selection === covered ? range$1(-10, 0) : range$1(0, 11);
67667 var layergroup = selection.selectAll('g.layergroup').data(range);
67668 layergroup = layergroup.enter().append('g').attr('class', function (d) {
67669 return 'layergroup layer' + String(d);
67670 }).merge(layergroup);
67671 layergroup.selectAll('g.linegroup').data(['shadow', 'casing', 'stroke', 'shadow-highlighted', 'casing-highlighted', 'stroke-highlighted']).enter().append('g').attr('class', function (d) {
67672 return 'linegroup line-' + d;
67674 layergroup.selectAll('g.line-shadow').call(drawLineGroup, 'shadow', false);
67675 layergroup.selectAll('g.line-casing').call(drawLineGroup, 'casing', false);
67676 layergroup.selectAll('g.line-stroke').call(drawLineGroup, 'stroke', false);
67677 layergroup.selectAll('g.line-shadow-highlighted').call(drawLineGroup, 'shadow', true);
67678 layergroup.selectAll('g.line-casing-highlighted').call(drawLineGroup, 'casing', true);
67679 layergroup.selectAll('g.line-stroke-highlighted').call(drawLineGroup, 'stroke', true);
67680 addMarkers(layergroup, 'oneway', 'onewaygroup', onewaydata, 'url(#ideditor-oneway-marker)');
67681 addMarkers(layergroup, 'sided', 'sidedgroup', sideddata, function marker(d) {
67682 var category = graph.entity(d.id).sidednessIdentifier();
67683 return 'url(#ideditor-sided-marker-' + category + ')';
67685 }); // Draw touch targets..
67687 touchLayer.call(drawTargets, graph, ways, filter);
67693 function svgMidpoints(projection, context) {
67694 var targetRadius = 8;
67696 function drawTargets(selection, graph, entities, filter) {
67697 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67698 var getTransform = svgPointTransform(projection).geojson;
67699 var data = entities.map(function (midpoint) {
67709 coordinates: midpoint.loc
67713 var targets = selection.selectAll('.midpoint.target').filter(function (d) {
67714 return filter(d.properties.entity);
67715 }).data(data, function key(d) {
67719 targets.exit().remove(); // enter/update
67721 targets.enter().append('circle').attr('r', targetRadius).merge(targets).attr('class', function (d) {
67722 return 'node midpoint target ' + fillClass + d.id;
67723 }).attr('transform', getTransform);
67726 function drawMidpoints(selection, graph, entities, filter, extent) {
67727 var drawLayer = selection.selectAll('.layer-osm.points .points-group.midpoints');
67728 var touchLayer = selection.selectAll('.layer-touch.points');
67729 var mode = context.mode();
67731 if (mode && mode.id !== 'select' || !context.map().withinEditableZoom()) {
67732 drawLayer.selectAll('.midpoint').remove();
67733 touchLayer.selectAll('.midpoint.target').remove();
67737 var poly = extent.polygon();
67738 var midpoints = {};
67740 for (var i = 0; i < entities.length; i++) {
67741 var entity = entities[i];
67742 if (entity.type !== 'way') continue;
67743 if (!filter(entity)) continue;
67744 if (context.selectedIDs().indexOf(entity.id) < 0) continue;
67745 var nodes = graph.childNodes(entity);
67747 for (var j = 0; j < nodes.length - 1; j++) {
67749 var b = nodes[j + 1];
67750 var id = [a.id, b.id].sort().join('-');
67752 if (midpoints[id]) {
67753 midpoints[id].parents.push(entity);
67754 } else if (geoVecLength(projection(a.loc), projection(b.loc)) > 40) {
67755 var point = geoVecInterp(a.loc, b.loc, 0.5);
67758 if (extent.intersects(point)) {
67761 for (var k = 0; k < 4; k++) {
67762 point = geoLineIntersection([a.loc, b.loc], [poly[k], poly[k + 1]]);
67764 if (point && geoVecLength(projection(a.loc), projection(point)) > 20 && geoVecLength(projection(b.loc), projection(point)) > 20) {
67776 edge: [a.id, b.id],
67784 function midpointFilter(d) {
67785 if (midpoints[d.id]) return true;
67787 for (var i = 0; i < d.parents.length; i++) {
67788 if (filter(d.parents[i])) {
67796 var groups = drawLayer.selectAll('.midpoint').filter(midpointFilter).data(Object.values(midpoints), function (d) {
67799 groups.exit().remove();
67800 var enter = groups.enter().insert('g', ':first-child').attr('class', 'midpoint');
67801 enter.append('polygon').attr('points', '-6,8 10,0 -6,-8').attr('class', 'shadow');
67802 enter.append('polygon').attr('points', '-3,4 5,0 -3,-4').attr('class', 'fill');
67803 groups = groups.merge(enter).attr('transform', function (d) {
67804 var translate = svgPointTransform(projection);
67805 var a = graph.entity(d.edge[0]);
67806 var b = graph.entity(d.edge[1]);
67807 var angle = geoAngle(a, b, projection) * (180 / Math.PI);
67808 return translate(d) + ' rotate(' + angle + ')';
67809 }).call(svgTagClasses().tags(function (d) {
67810 return d.parents[0].tags;
67811 })); // Propagate data bindings.
67813 groups.select('polygon.shadow');
67814 groups.select('polygon.fill'); // Draw touch targets..
67816 touchLayer.call(drawTargets, graph, Object.values(midpoints), midpointFilter);
67819 return drawMidpoints;
67822 function svgPoints(projection, context) {
67823 function markerPath(selection, klass) {
67824 selection.attr('class', klass).attr('transform', 'translate(-8, -23)').attr('d', 'M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z');
67827 function sortY(a, b) {
67828 return b.loc[1] - a.loc[1];
67829 } // Avoid exit/enter if we're just moving stuff around.
67830 // The node will get a new version but we only need to run the update selection.
67833 function fastEntityKey(d) {
67834 var mode = context.mode();
67835 var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
67836 return isMoving ? d.id : osmEntity.key(d);
67839 function drawTargets(selection, graph, entities, filter) {
67840 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67841 var getTransform = svgPointTransform(projection).geojson;
67842 var activeID = context.activeID();
67844 entities.forEach(function (node) {
67845 if (activeID === node.id) return; // draw no target on the activeID
67854 geometry: node.asGeoJSON()
67857 var targets = selection.selectAll('.point.target').filter(function (d) {
67858 return filter(d.properties.entity);
67859 }).data(data, function key(d) {
67863 targets.exit().remove(); // enter/update
67865 targets.enter().append('rect').attr('x', -10).attr('y', -26).attr('width', 20).attr('height', 30).merge(targets).attr('class', function (d) {
67866 return 'node point target ' + fillClass + d.id;
67867 }).attr('transform', getTransform);
67870 function drawPoints(selection, graph, entities, filter) {
67871 var wireframe = context.surface().classed('fill-wireframe');
67872 var zoom = geoScaleToZoom(projection.scale());
67873 var base = context.history().base(); // Points with a direction will render as vertices at higher zooms..
67875 function renderAsPoint(entity) {
67876 return entity.geometry(graph) === 'point' && !(zoom >= 18 && entity.directions(graph, projection).length);
67877 } // All points will render as vertices in wireframe mode too..
67880 var points = wireframe ? [] : entities.filter(renderAsPoint);
67881 points.sort(sortY);
67882 var drawLayer = selection.selectAll('.layer-osm.points .points-group.points');
67883 var touchLayer = selection.selectAll('.layer-touch.points'); // Draw points..
67885 var groups = drawLayer.selectAll('g.point').filter(filter).data(points, fastEntityKey);
67886 groups.exit().remove();
67887 var enter = groups.enter().append('g').attr('class', function (d) {
67888 return 'node point ' + d.id;
67890 enter.append('path').call(markerPath, 'shadow');
67891 enter.append('ellipse').attr('cx', 0.5).attr('cy', 1).attr('rx', 6.5).attr('ry', 3).attr('class', 'stroke');
67892 enter.append('path').call(markerPath, 'stroke');
67893 enter.append('use').attr('transform', 'translate(-5, -19)').attr('class', 'icon').attr('width', '11px').attr('height', '11px');
67894 groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('added', function (d) {
67895 return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
67896 }).classed('moved', function (d) {
67897 return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
67898 }).classed('retagged', function (d) {
67899 return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
67900 }).call(svgTagClasses());
67901 groups.select('.shadow'); // propagate bound data
67903 groups.select('.stroke'); // propagate bound data
67905 groups.select('.icon') // propagate bound data
67906 .attr('xlink:href', function (entity) {
67907 var preset = _mainPresetIndex.match(entity, graph);
67908 var picon = preset && preset.icon;
67913 var isMaki = /^maki-/.test(picon);
67914 return '#' + picon + (isMaki ? '-11' : '');
67916 }); // Draw touch targets..
67918 touchLayer.call(drawTargets, graph, points, filter);
67924 function svgTurns(projection, context) {
67925 function icon(turn) {
67926 var u = turn.u ? '-u' : '';
67927 if (turn.no) return '#iD-turn-no' + u;
67928 if (turn.only) return '#iD-turn-only' + u;
67929 return '#iD-turn-yes' + u;
67932 function drawTurns(selection, graph, turns) {
67933 function turnTransform(d) {
67935 var toWay = graph.entity(d.to.way);
67936 var toPoints = graph.childNodes(toWay).map(function (n) {
67938 }).map(projection);
67939 var toLength = geoPathLength(toPoints);
67940 var mid = toLength / 2; // midpoint of destination way
67942 var toNode = graph.entity(d.to.node);
67943 var toVertex = graph.entity(d.to.vertex);
67944 var a = geoAngle(toVertex, toNode, projection);
67945 var o = projection(toVertex.loc);
67946 var r = d.u ? 0 // u-turn: no radius
67947 : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius
67948 : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways
67950 return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')';
67953 var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns');
67954 var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns..
67956 var groups = drawLayer.selectAll('g.turn').data(turns, function (d) {
67960 groups.exit().remove(); // enter
67962 var groupsEnter = groups.enter().append('g').attr('class', function (d) {
67963 return 'turn ' + d.key;
67965 var turnsEnter = groupsEnter.filter(function (d) {
67968 turnsEnter.append('rect').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67969 turnsEnter.append('use').attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67970 var uEnter = groupsEnter.filter(function (d) {
67973 uEnter.append('circle').attr('r', '16');
67974 uEnter.append('use').attr('transform', 'translate(-16, -16)').attr('width', '32').attr('height', '32'); // update
67976 groups = groups.merge(groupsEnter).attr('opacity', function (d) {
67977 return d.direct === false ? '0.7' : null;
67978 }).attr('transform', turnTransform);
67979 groups.select('use').attr('xlink:href', icon);
67980 groups.select('rect'); // propagate bound data
67982 groups.select('circle'); // propagate bound data
67983 // Draw touch targets..
67985 var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
67986 groups = touchLayer.selectAll('g.turn').data(turns, function (d) {
67990 groups.exit().remove(); // enter
67992 groupsEnter = groups.enter().append('g').attr('class', function (d) {
67993 return 'turn ' + d.key;
67995 turnsEnter = groupsEnter.filter(function (d) {
67998 turnsEnter.append('rect').attr('class', 'target ' + fillClass).attr('transform', 'translate(-22, -12)').attr('width', '44').attr('height', '24');
67999 uEnter = groupsEnter.filter(function (d) {
68002 uEnter.append('circle').attr('class', 'target ' + fillClass).attr('r', '16'); // update
68004 groups = groups.merge(groupsEnter).attr('transform', turnTransform);
68005 groups.select('rect'); // propagate bound data
68007 groups.select('circle'); // propagate bound data
68015 function svgVertices(projection, context) {
68017 // z16-, z17, z18+, w/icon
68018 shadow: [6, 7.5, 7.5, 12],
68019 stroke: [2.5, 3.5, 3.5, 8],
68020 fill: [1, 1.5, 1.5, 1.5]
68023 var _currHoverTarget;
68025 var _currPersistent = {};
68026 var _currHover = {};
68027 var _prevHover = {};
68028 var _currSelected = {};
68029 var _prevSelected = {};
68032 function sortY(a, b) {
68033 return b.loc[1] - a.loc[1];
68034 } // Avoid exit/enter if we're just moving stuff around.
68035 // The node will get a new version but we only need to run the update selection.
68038 function fastEntityKey(d) {
68039 var mode = context.mode();
68040 var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
68041 return isMoving ? d.id : osmEntity.key(d);
68044 function draw(selection, graph, vertices, sets, filter) {
68051 var directions = {};
68052 var wireframe = context.surface().classed('fill-wireframe');
68053 var zoom = geoScaleToZoom(projection.scale());
68054 var z = zoom < 17 ? 0 : zoom < 18 ? 1 : 2;
68055 var activeID = context.activeID();
68056 var base = context.history().base();
68058 function getIcon(d) {
68059 // always check latest entity, as fastEntityKey avoids enter/exit now
68060 var entity = graph.entity(d.id);
68061 if (entity.id in icons) return icons[entity.id];
68062 icons[entity.id] = entity.hasInterestingTags() && _mainPresetIndex.match(entity, graph).icon;
68063 return icons[entity.id];
68064 } // memoize directions results, return false for empty arrays (for use in filter)
68067 function getDirections(entity) {
68068 if (entity.id in directions) return directions[entity.id];
68069 var angles = entity.directions(graph, projection);
68070 directions[entity.id] = angles.length ? angles : false;
68074 function updateAttributes(selection) {
68075 ['shadow', 'stroke', 'fill'].forEach(function (klass) {
68076 var rads = radiuses[klass];
68077 selection.selectAll('.' + klass).each(function (entity) {
68078 var i = z && getIcon(entity);
68079 var r = rads[i ? 3 : z]; // slightly increase the size of unconnected endpoints #3775
68081 if (entity.id !== activeID && entity.isEndpoint(graph) && !entity.isConnected(graph)) {
68085 if (klass === 'shadow') {
68086 // remember this value, so we don't need to
68087 _radii[entity.id] = r; // recompute it when we draw the touch targets
68090 select(this).attr('r', r).attr('visibility', i && klass === 'fill' ? 'hidden' : null);
68095 vertices.sort(sortY);
68096 var groups = selection.selectAll('g.vertex').filter(filter).data(vertices, fastEntityKey); // exit
68098 groups.exit().remove(); // enter
68100 var enter = groups.enter().append('g').attr('class', function (d) {
68101 return 'node vertex ' + d.id;
68103 enter.append('circle').attr('class', 'shadow');
68104 enter.append('circle').attr('class', 'stroke'); // Vertices with tags get a fill.
68106 enter.filter(function (d) {
68107 return d.hasInterestingTags();
68108 }).append('circle').attr('class', 'fill'); // update
68110 groups = groups.merge(enter).attr('transform', svgPointTransform(projection)).classed('sibling', function (d) {
68111 return d.id in sets.selected;
68112 }).classed('shared', function (d) {
68113 return graph.isShared(d);
68114 }).classed('endpoint', function (d) {
68115 return d.isEndpoint(graph);
68116 }).classed('added', function (d) {
68117 return !base.entities[d.id]; // if it doesn't exist in the base graph, it's new
68118 }).classed('moved', function (d) {
68119 return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].loc, base.entities[d.id].loc);
68120 }).classed('retagged', function (d) {
68121 return base.entities[d.id] && !fastDeepEqual(graph.entities[d.id].tags, base.entities[d.id].tags);
68122 }).call(updateAttributes); // Vertices with icons get a `use`.
68124 var iconUse = groups.selectAll('.icon').data(function data(d) {
68125 return zoom >= 17 && getIcon(d) ? [d] : [];
68126 }, fastEntityKey); // exit
68128 iconUse.exit().remove(); // enter
68130 iconUse.enter().append('use').attr('class', 'icon').attr('width', '11px').attr('height', '11px').attr('transform', 'translate(-5.5, -5.5)').attr('xlink:href', function (d) {
68131 var picon = getIcon(d);
68132 var isMaki = /^maki-/.test(picon);
68133 return '#' + picon + (isMaki ? '-11' : '');
68134 }); // Vertices with directions get viewfields
68136 var dgroups = groups.selectAll('.viewfieldgroup').data(function data(d) {
68137 return zoom >= 18 && getDirections(d) ? [d] : [];
68138 }, fastEntityKey); // exit
68140 dgroups.exit().remove(); // enter/update
68142 dgroups = dgroups.enter().insert('g', '.shadow').attr('class', 'viewfieldgroup').merge(dgroups);
68143 var viewfields = dgroups.selectAll('.viewfield').data(getDirections, function key(d) {
68144 return osmEntity.key(d);
68147 viewfields.exit().remove(); // enter/update
68149 viewfields.enter().append('path').attr('class', 'viewfield').attr('d', 'M0,0H0').merge(viewfields).attr('marker-start', 'url(#ideditor-viewfield-marker' + (wireframe ? '-wireframe' : '') + ')').attr('transform', function (d) {
68150 return 'rotate(' + d + ')';
68154 function drawTargets(selection, graph, entities, filter) {
68155 var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
68156 var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
68157 var getTransform = svgPointTransform(projection).geojson;
68158 var activeID = context.activeID();
68163 entities.forEach(function (node) {
68164 if (activeID === node.id) return; // draw no target on the activeID
68166 var vertexType = svgPassiveVertex(node, graph, activeID);
68168 if (vertexType !== 0) {
68169 // passive or adjacent - allow to connect
68170 data.targets.push({
68177 geometry: node.asGeoJSON()
68182 id: node.id + '-nope',
68188 geometry: node.asGeoJSON()
68191 }); // Targets allow hover and vertex snapping
68193 var targets = selection.selectAll('.vertex.target-allowed').filter(function (d) {
68194 return filter(d.properties.entity);
68195 }).data(data.targets, function key(d) {
68199 targets.exit().remove(); // enter/update
68201 targets.enter().append('circle').attr('r', function (d) {
68202 return _radii[d.id] || radiuses.shadow[3];
68203 }).merge(targets).attr('class', function (d) {
68204 return 'node vertex target target-allowed ' + targetClass + d.id;
68205 }).attr('transform', getTransform); // NOPE
68207 var nopes = selection.selectAll('.vertex.target-nope').filter(function (d) {
68208 return filter(d.properties.entity);
68209 }).data(data.nopes, function key(d) {
68213 nopes.exit().remove(); // enter/update
68215 nopes.enter().append('circle').attr('r', function (d) {
68216 return _radii[d.properties.entity.id] || radiuses.shadow[3];
68217 }).merge(nopes).attr('class', function (d) {
68218 return 'node vertex target target-nope ' + nopeClass + d.id;
68219 }).attr('transform', getTransform);
68220 } // Points can also render as vertices:
68221 // 1. in wireframe mode or
68222 // 2. at higher zooms if they have a direction
68225 function renderAsVertex(entity, graph, wireframe, zoom) {
68226 var geometry = entity.geometry(graph);
68227 return geometry === 'vertex' || geometry === 'point' && (wireframe || zoom >= 18 && entity.directions(graph, projection).length);
68230 function isEditedNode(node, base, head) {
68231 var baseNode = base.entities[node.id];
68232 var headNode = head.entities[node.id];
68233 return !headNode || !baseNode || !fastDeepEqual(headNode.tags, baseNode.tags) || !fastDeepEqual(headNode.loc, baseNode.loc);
68236 function getSiblingAndChildVertices(ids, graph, wireframe, zoom) {
68240 function addChildVertices(entity) {
68241 // avoid redundant work and infinite recursion of circular relations
68242 if (seenIds[entity.id]) return;
68243 seenIds[entity.id] = true;
68244 var geometry = entity.geometry(graph);
68246 if (!context.features().isHiddenFeature(entity, graph, geometry)) {
68249 if (entity.type === 'way') {
68250 for (i = 0; i < entity.nodes.length; i++) {
68251 var child = graph.hasEntity(entity.nodes[i]);
68254 addChildVertices(child);
68257 } else if (entity.type === 'relation') {
68258 for (i = 0; i < entity.members.length; i++) {
68259 var member = graph.hasEntity(entity.members[i].id);
68262 addChildVertices(member);
68265 } else if (renderAsVertex(entity, graph, wireframe, zoom)) {
68266 results[entity.id] = entity;
68271 ids.forEach(function (id) {
68272 var entity = graph.hasEntity(id);
68273 if (!entity) return;
68275 if (entity.type === 'node') {
68276 if (renderAsVertex(entity, graph, wireframe, zoom)) {
68277 results[entity.id] = entity;
68278 graph.parentWays(entity).forEach(function (entity) {
68279 addChildVertices(entity);
68284 addChildVertices(entity);
68290 function drawVertices(selection, graph, entities, filter, extent, fullRedraw) {
68291 var wireframe = context.surface().classed('fill-wireframe');
68292 var visualDiff = context.surface().classed('highlight-edited');
68293 var zoom = geoScaleToZoom(projection.scale());
68294 var mode = context.mode();
68295 var isMoving = mode && /^(add|draw|drag|move|rotate)/.test(mode.id);
68296 var base = context.history().base();
68297 var drawLayer = selection.selectAll('.layer-osm.points .points-group.vertices');
68298 var touchLayer = selection.selectAll('.layer-touch.points');
68301 _currPersistent = {};
68303 } // Collect important vertices from the `entities` list..
68304 // (during a partial redraw, it will not contain everything)
68307 for (var i = 0; i < entities.length; i++) {
68308 var entity = entities[i];
68309 var geometry = entity.geometry(graph);
68310 var keep = false; // a point that looks like a vertex..
68312 if (geometry === 'point' && renderAsVertex(entity, graph, wireframe, zoom)) {
68313 _currPersistent[entity.id] = entity;
68314 keep = true; // a vertex of some importance..
68315 } else if (geometry === 'vertex' && (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph) || visualDiff && isEditedNode(entity, base, graph))) {
68316 _currPersistent[entity.id] = entity;
68318 } // whatever this is, it's not a persistent vertex..
68321 if (!keep && !fullRedraw) {
68322 delete _currPersistent[entity.id];
68324 } // 3 sets of vertices to consider:
68328 persistent: _currPersistent,
68329 // persistent = important vertices (render always)
68330 selected: _currSelected,
68331 // selected + siblings of selected (render always)
68332 hovered: _currHover // hovered + siblings of hovered (render only in draw modes)
68335 var all = Object.assign({}, isMoving ? _currHover : {}, _currSelected, _currPersistent); // Draw the vertices..
68336 // The filter function controls the scope of what objects d3 will touch (exit/enter/update)
68337 // Adjust the filter function to expand the scope beyond whatever entities were passed in.
68339 var filterRendered = function filterRendered(d) {
68340 return d.id in _currPersistent || d.id in _currSelected || d.id in _currHover || filter(d);
68343 drawLayer.call(draw, graph, currentVisible(all), sets, filterRendered); // Draw touch targets..
68344 // When drawing, render all targets (not just those affected by a partial redraw)
68346 var filterTouch = function filterTouch(d) {
68347 return isMoving ? true : filterRendered(d);
68350 touchLayer.call(drawTargets, graph, currentVisible(all), filterTouch);
68352 function currentVisible(which) {
68353 return Object.keys(which).map(graph.hasEntity, graph) // the current version of this entity
68354 .filter(function (entity) {
68355 return entity && entity.intersects(extent, graph);
68358 } // partial redraw - only update the selected items..
68361 drawVertices.drawSelected = function (selection, graph, extent) {
68362 var wireframe = context.surface().classed('fill-wireframe');
68363 var zoom = geoScaleToZoom(projection.scale());
68364 _prevSelected = _currSelected || {};
68366 if (context.map().isInWideSelection()) {
68367 _currSelected = {};
68368 context.selectedIDs().forEach(function (id) {
68369 var entity = graph.hasEntity(id);
68370 if (!entity) return;
68372 if (entity.type === 'node') {
68373 if (renderAsVertex(entity, graph, wireframe, zoom)) {
68374 _currSelected[entity.id] = entity;
68379 _currSelected = getSiblingAndChildVertices(context.selectedIDs(), graph, wireframe, zoom);
68380 } // note that drawVertices will add `_currSelected` automatically if needed..
68383 var filter = function filter(d) {
68384 return d.id in _prevSelected;
68387 drawVertices(selection, graph, Object.values(_prevSelected), filter, extent, false);
68388 }; // partial redraw - only update the hovered items..
68391 drawVertices.drawHover = function (selection, graph, target, extent) {
68392 if (target === _currHoverTarget) return; // continue only if something changed
68394 var wireframe = context.surface().classed('fill-wireframe');
68395 var zoom = geoScaleToZoom(projection.scale());
68396 _prevHover = _currHover || {};
68397 _currHoverTarget = target;
68398 var entity = target && target.properties && target.properties.entity;
68401 _currHover = getSiblingAndChildVertices([entity.id], graph, wireframe, zoom);
68404 } // note that drawVertices will add `_currHover` automatically if needed..
68407 var filter = function filter(d) {
68408 return d.id in _prevHover;
68411 drawVertices(selection, graph, Object.values(_prevHover), filter, extent, false);
68414 return drawVertices;
68417 function utilBindOnce(target, type, listener, capture) {
68418 var typeOnce = type + '.once';
68421 target.on(typeOnce, null);
68422 listener.apply(this, arguments);
68425 target.on(typeOnce, one, capture);
68429 function defaultFilter(d3_event) {
68430 return !d3_event.ctrlKey && !d3_event.button;
68433 function defaultExtent() {
68436 if (e instanceof SVGElement) {
68437 e = e.ownerSVGElement || e;
68439 if (e.hasAttribute('viewBox')) {
68440 e = e.viewBox.baseVal;
68441 return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
68444 return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
68447 return [[0, 0], [e.clientWidth, e.clientHeight]];
68450 function defaultWheelDelta(d3_event) {
68451 return -d3_event.deltaY * (d3_event.deltaMode === 1 ? 0.05 : d3_event.deltaMode ? 1 : 0.002);
68454 function defaultConstrain(transform, extent, translateExtent) {
68455 var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0],
68456 dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0],
68457 dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1],
68458 dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
68459 return transform.translate(dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1), dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1));
68462 function utilZoomPan() {
68463 var filter = defaultFilter,
68464 extent = defaultExtent,
68465 constrain = defaultConstrain,
68466 wheelDelta = defaultWheelDelta,
68467 scaleExtent = [0, Infinity],
68468 translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]],
68469 interpolate = interpolateZoom,
68470 dispatch = dispatch$8('start', 'zoom', 'end'),
68472 _transform = identity$2,
68475 function zoom(selection) {
68476 selection.on('pointerdown.zoom', pointerdown).on('wheel.zoom', wheeled).style('touch-action', 'none').style('-webkit-tap-highlight-color', 'rgba(0,0,0,0)');
68477 select(window).on('pointermove.zoompan', pointermove).on('pointerup.zoompan pointercancel.zoompan', pointerup);
68480 zoom.transform = function (collection, transform, point) {
68481 var selection = collection.selection ? collection.selection() : collection;
68483 if (collection !== selection) {
68484 schedule(collection, transform, point);
68486 selection.interrupt().each(function () {
68487 gesture(this, arguments).start(null).zoom(null, null, typeof transform === 'function' ? transform.apply(this, arguments) : transform).end(null);
68492 zoom.scaleBy = function (selection, k, p) {
68493 zoom.scaleTo(selection, function () {
68494 var k0 = _transform.k,
68495 k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
68500 zoom.scaleTo = function (selection, k, p) {
68501 zoom.transform(selection, function () {
68502 var e = extent.apply(this, arguments),
68504 p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p,
68505 p1 = t0.invert(p0),
68506 k1 = typeof k === 'function' ? k.apply(this, arguments) : k;
68507 return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
68511 zoom.translateBy = function (selection, x, y) {
68512 zoom.transform(selection, function () {
68513 return constrain(_transform.translate(typeof x === 'function' ? x.apply(this, arguments) : x, typeof y === 'function' ? y.apply(this, arguments) : y), extent.apply(this, arguments), translateExtent);
68517 zoom.translateTo = function (selection, x, y, p) {
68518 zoom.transform(selection, function () {
68519 var e = extent.apply(this, arguments),
68521 p0 = !p ? centroid(e) : typeof p === 'function' ? p.apply(this, arguments) : p;
68522 return constrain(identity$2.translate(p0[0], p0[1]).scale(t.k).translate(typeof x === 'function' ? -x.apply(this, arguments) : -x, typeof y === 'function' ? -y.apply(this, arguments) : -y), e, translateExtent);
68526 function scale(transform, k) {
68527 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
68528 return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
68531 function translate(transform, p0, p1) {
68532 var x = p0[0] - p1[0] * transform.k,
68533 y = p0[1] - p1[1] * transform.k;
68534 return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
68537 function centroid(extent) {
68538 return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
68541 function schedule(transition, transform, point) {
68542 transition.on('start.zoom', function () {
68543 gesture(this, arguments).start(null);
68544 }).on('interrupt.zoom end.zoom', function () {
68545 gesture(this, arguments).end(null);
68546 }).tween('zoom', function () {
68549 g = gesture(that, args),
68550 e = extent.apply(that, args),
68551 p = !point ? centroid(e) : typeof point === 'function' ? point.apply(that, args) : point,
68552 w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
68554 b = typeof transform === 'function' ? transform.apply(that, args) : transform,
68555 i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
68556 return function (t) {
68558 // Avoid rounding error on end.
68563 t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
68566 g.zoom(null, null, t);
68571 function gesture(that, args, clean) {
68572 return !clean && _activeGesture || new Gesture(that, args);
68575 function Gesture(that, args) {
68579 this.extent = extent.apply(that, args);
68582 Gesture.prototype = {
68583 start: function start(d3_event) {
68584 if (++this.active === 1) {
68585 _activeGesture = this;
68586 dispatch.call('start', this, d3_event);
68591 zoom: function zoom(d3_event, key, transform) {
68592 if (this.mouse && key !== 'mouse') this.mouse[1] = transform.invert(this.mouse[0]);
68593 if (this.pointer0 && key !== 'touch') this.pointer0[1] = transform.invert(this.pointer0[0]);
68594 if (this.pointer1 && key !== 'touch') this.pointer1[1] = transform.invert(this.pointer1[0]);
68595 _transform = transform;
68596 dispatch.call('zoom', this, d3_event, key, transform);
68599 end: function end(d3_event) {
68600 if (--this.active === 0) {
68601 _activeGesture = null;
68602 dispatch.call('end', this, d3_event);
68609 function wheeled(d3_event) {
68610 if (!filter.apply(this, arguments)) return;
68611 var g = gesture(this, arguments),
68613 k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))),
68614 p = utilFastMouse(this)(d3_event); // If the mouse is in the same location as before, reuse it.
68615 // If there were recent wheel events, reset the wheel idle timeout.
68618 if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
68619 g.mouse[1] = t.invert(g.mouse[0] = p);
68622 clearTimeout(g.wheel); // Otherwise, capture the mouse point and location at the start.
68624 g.mouse = [p, t.invert(p)];
68629 d3_event.preventDefault();
68630 d3_event.stopImmediatePropagation();
68631 g.wheel = setTimeout(wheelidled, _wheelDelay);
68632 g.zoom(d3_event, 'mouse', constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
68634 function wheelidled() {
68640 var _downPointerIDs = new Set();
68642 var _pointerLocGetter;
68644 function pointerdown(d3_event) {
68645 _downPointerIDs.add(d3_event.pointerId);
68647 if (!filter.apply(this, arguments)) return;
68648 var g = gesture(this, arguments, _downPointerIDs.size === 1);
68650 d3_event.stopImmediatePropagation();
68651 _pointerLocGetter = utilFastMouse(this);
68653 var loc = _pointerLocGetter(d3_event);
68655 var p = [loc, _transform.invert(loc), d3_event.pointerId];
68660 } else if (!g.pointer1 && g.pointer0[2] !== p[2]) {
68670 function pointermove(d3_event) {
68671 if (!_downPointerIDs.has(d3_event.pointerId)) return;
68672 if (!_activeGesture || !_pointerLocGetter) return;
68673 var g = gesture(this, arguments);
68674 var isPointer0 = g.pointer0 && g.pointer0[2] === d3_event.pointerId;
68675 var isPointer1 = !isPointer0 && g.pointer1 && g.pointer1[2] === d3_event.pointerId;
68677 if ((isPointer0 || isPointer1) && 'buttons' in d3_event && !d3_event.buttons) {
68678 // The pointer went up without ending the gesture somehow, e.g.
68679 // a down mouse was moved off the map and released. End it here.
68680 if (g.pointer0) _downPointerIDs["delete"](g.pointer0[2]);
68681 if (g.pointer1) _downPointerIDs["delete"](g.pointer1[2]);
68686 d3_event.preventDefault();
68687 d3_event.stopImmediatePropagation();
68689 var loc = _pointerLocGetter(d3_event);
68692 if (isPointer0) g.pointer0[0] = loc;else if (isPointer1) g.pointer1[0] = loc;
68696 var p0 = g.pointer0[0],
68697 l0 = g.pointer0[1],
68698 p1 = g.pointer1[0],
68699 l1 = g.pointer1[1],
68700 dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
68701 dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
68702 t = scale(t, Math.sqrt(dp / dl));
68703 p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
68704 l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
68705 } else if (g.pointer0) {
68712 g.zoom(d3_event, 'touch', constrain(translate(t, p, l), g.extent, translateExtent));
68715 function pointerup(d3_event) {
68716 if (!_downPointerIDs.has(d3_event.pointerId)) return;
68718 _downPointerIDs["delete"](d3_event.pointerId);
68720 if (!_activeGesture) return;
68721 var g = gesture(this, arguments);
68722 d3_event.stopImmediatePropagation();
68723 if (g.pointer0 && g.pointer0[2] === d3_event.pointerId) delete g.pointer0;else if (g.pointer1 && g.pointer1[2] === d3_event.pointerId) delete g.pointer1;
68725 if (g.pointer1 && !g.pointer0) {
68726 g.pointer0 = g.pointer1;
68731 g.pointer0[1] = _transform.invert(g.pointer0[0]);
68737 zoom.wheelDelta = function (_) {
68738 return arguments.length ? (wheelDelta = utilFunctor(+_), zoom) : wheelDelta;
68741 zoom.filter = function (_) {
68742 return arguments.length ? (filter = utilFunctor(!!_), zoom) : filter;
68745 zoom.extent = function (_) {
68746 return arguments.length ? (extent = utilFunctor([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
68749 zoom.scaleExtent = function (_) {
68750 return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
68753 zoom.translateExtent = function (_) {
68754 return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
68757 zoom.constrain = function (_) {
68758 return arguments.length ? (constrain = _, zoom) : constrain;
68761 zoom.interpolate = function (_) {
68762 return arguments.length ? (interpolate = _, zoom) : interpolate;
68765 zoom._transform = function (_) {
68766 return arguments.length ? (_transform = _, zoom) : _transform;
68769 return utilRebind(zoom, dispatch, 'on');
68772 // if pointer events are supported. Falls back to default `dblclick` event.
68774 function utilDoubleUp() {
68775 var dispatch = dispatch$8('doubleUp');
68776 var _maxTimespan = 500; // milliseconds
68778 var _maxDistance = 20; // web pixels; be somewhat generous to account for touch devices
68780 var _pointer; // object representing the pointer that could trigger double up
68783 function pointerIsValidFor(loc) {
68784 // second pointerup must occur within a small timeframe after the first pointerdown
68785 return new Date().getTime() - _pointer.startTime <= _maxTimespan && // all pointer events must occur within a small distance of the first pointerdown
68786 geoVecLength(_pointer.startLoc, loc) <= _maxDistance;
68789 function pointerdown(d3_event) {
68790 // ignore right-click
68791 if (d3_event.ctrlKey || d3_event.button === 2) return;
68792 var loc = [d3_event.clientX, d3_event.clientY]; // Don't rely on pointerId here since it can change between pointerdown
68793 // events on touch devices
68795 if (_pointer && !pointerIsValidFor(loc)) {
68796 // if this pointer is no longer valid, clear it so another can be started
68797 _pointer = undefined;
68803 startTime: new Date().getTime(),
68805 pointerId: d3_event.pointerId
68809 _pointer.pointerId = d3_event.pointerId;
68813 function pointerup(d3_event) {
68814 // ignore right-click
68815 if (d3_event.ctrlKey || d3_event.button === 2) return;
68816 if (!_pointer || _pointer.pointerId !== d3_event.pointerId) return;
68817 _pointer.upCount += 1;
68819 if (_pointer.upCount === 2) {
68821 var loc = [d3_event.clientX, d3_event.clientY];
68823 if (pointerIsValidFor(loc)) {
68824 var locInThis = utilFastMouse(this)(d3_event);
68825 dispatch.call('doubleUp', this, d3_event, locInThis);
68826 } // clear the pointer info in any case
68829 _pointer = undefined;
68833 function doubleUp(selection) {
68834 if ('PointerEvent' in window) {
68835 // dblclick isn't well supported on touch devices so manually use
68836 // pointer events if they're available
68837 selection.on('pointerdown.doubleUp', pointerdown).on('pointerup.doubleUp', pointerup);
68839 // fallback to dblclick
68840 selection.on('dblclick.doubleUp', function (d3_event) {
68841 dispatch.call('doubleUp', this, d3_event, utilFastMouse(this)(d3_event));
68846 doubleUp.off = function (selection) {
68847 selection.on('pointerdown.doubleUp', null).on('pointerup.doubleUp', null).on('dblclick.doubleUp', null);
68850 return utilRebind(doubleUp, dispatch, 'on');
68853 var TILESIZE = 256;
68856 var kMin = geoZoomToScale(minZoom, TILESIZE);
68857 var kMax = geoZoomToScale(maxZoom, TILESIZE);
68859 function clamp$1(num, min, max) {
68860 return Math.max(min, Math.min(num, max));
68863 function rendererMap(context) {
68864 var dispatch = dispatch$8('move', 'drawn', 'crossEditableZoom', 'hitMinZoom', 'changeHighlighting', 'changeAreaFill');
68865 var projection = context.projection;
68866 var curtainProjection = context.curtainProjection;
68875 var _selection = select(null);
68877 var supersurface = select(null);
68878 var wrapper = select(null);
68879 var surface = select(null);
68880 var _dimensions = [1, 1];
68881 var _dblClickZoomEnabled = true;
68882 var _redrawEnabled = true;
68884 var _gestureTransformStart;
68886 var _transformStart = projection.transform();
68888 var _transformLast;
68890 var _isTransformed = false;
68893 var _getMouseCoords;
68895 var _lastPointerEvent;
68897 var _lastWithinEditableZoom; // whether a pointerdown event started the zoom
68900 var _pointerDown = false; // use pointer events on supported platforms; fallback to mouse events
68902 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // use pointer event interaction if supported; fallback to touch/mouse events in d3-zoom
68905 var _zoomerPannerFunction = 'PointerEvent' in window ? utilZoomPan : d3_zoom;
68907 var _zoomerPanner = _zoomerPannerFunction().scaleExtent([kMin, kMax]).interpolate(interpolate$1).filter(zoomEventFilter).on('zoom.map', zoomPan).on('start.map', function (d3_event) {
68908 _pointerDown = d3_event && (d3_event.type === 'pointerdown' || d3_event.sourceEvent && d3_event.sourceEvent.type === 'pointerdown');
68909 }).on('end.map', function () {
68910 _pointerDown = false;
68913 var _doubleUpHandler = utilDoubleUp();
68915 var scheduleRedraw = throttle(redraw, 750); // var isRedrawScheduled = false;
68916 // var pendingRedrawCall;
68917 // function scheduleRedraw() {
68918 // // Only schedule the redraw if one has not already been set.
68919 // if (isRedrawScheduled) return;
68920 // isRedrawScheduled = true;
68921 // var that = this;
68922 // var args = arguments;
68923 // pendingRedrawCall = window.requestIdleCallback(function () {
68924 // // Reset the boolean so future redraws can be set.
68925 // isRedrawScheduled = false;
68926 // redraw.apply(that, args);
68927 // }, { timeout: 1400 });
68931 function cancelPendingRedraw() {
68932 scheduleRedraw.cancel(); // isRedrawScheduled = false;
68933 // window.cancelIdleCallback(pendingRedrawCall);
68936 function map(selection) {
68937 _selection = selection;
68938 context.on('change.map', immediateRedraw);
68939 var osm = context.connection();
68942 osm.on('change.map', immediateRedraw);
68945 function didUndoOrRedo(targetTransform) {
68946 var mode = context.mode().id;
68947 if (mode !== 'browse' && mode !== 'select') return;
68949 if (targetTransform) {
68950 map.transformEase(targetTransform);
68954 context.history().on('merge.map', function () {
68956 }).on('change.map', immediateRedraw).on('undone.map', function (stack, fromStack) {
68957 didUndoOrRedo(fromStack.transform);
68958 }).on('redone.map', function (stack) {
68959 didUndoOrRedo(stack.transform);
68961 context.background().on('change.map', immediateRedraw);
68962 context.features().on('redraw.map', immediateRedraw);
68963 drawLayers.on('change.map', function () {
68964 context.background().updateImagery();
68967 selection.on('wheel.map mousewheel.map', function (d3_event) {
68968 // disable swipe-to-navigate browser pages on trackpad/magic mouse – #5552
68969 d3_event.preventDefault();
68970 }).call(_zoomerPanner).call(_zoomerPanner.transform, projection.transform()).on('dblclick.zoom', null); // override d3-zoom dblclick handling
68972 map.supersurface = supersurface = selection.append('div').attr('class', 'supersurface').call(utilSetTransform, 0, 0); // Need a wrapper div because Opera can't cope with an absolutely positioned
68973 // SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
68975 wrapper = supersurface.append('div').attr('class', 'layer layer-data');
68976 map.surface = surface = wrapper.call(drawLayers).selectAll('.surface');
68977 surface.call(drawLabels.observe).call(_doubleUpHandler).on(_pointerPrefix + 'down.zoom', function (d3_event) {
68978 _lastPointerEvent = d3_event;
68980 if (d3_event.button === 2) {
68981 d3_event.stopPropagation();
68983 }, true).on(_pointerPrefix + 'up.zoom', function (d3_event) {
68984 _lastPointerEvent = d3_event;
68986 if (resetTransform()) {
68989 }).on(_pointerPrefix + 'move.map', function (d3_event) {
68990 _lastPointerEvent = d3_event;
68991 }).on(_pointerPrefix + 'over.vertices', function (d3_event) {
68992 if (map.editableDataEnabled() && !_isTransformed) {
68993 var hover = d3_event.target.__data__;
68994 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
68995 dispatch.call('drawn', this, {
68999 }).on(_pointerPrefix + 'out.vertices', function (d3_event) {
69000 if (map.editableDataEnabled() && !_isTransformed) {
69001 var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__;
69002 surface.call(drawVertices.drawHover, context.graph(), hover, map.extent());
69003 dispatch.call('drawn', this, {
69008 var detected = utilDetect(); // only WebKit supports gesture events
69010 if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
69011 // but we only need to do this on desktop Safari anyway. – #7694
69012 !detected.isMobileWebKit) {
69013 // Desktop Safari sends gesture events for multitouch trackpad pinches.
69014 // We can listen for these and translate them into map zooms.
69015 surface.on('gesturestart.surface', function (d3_event) {
69016 d3_event.preventDefault();
69017 _gestureTransformStart = projection.transform();
69018 }).on('gesturechange.surface', gestureChange);
69019 } // must call after surface init
69024 _doubleUpHandler.on('doubleUp.map', function (d3_event, p0) {
69025 if (!_dblClickZoomEnabled) return; // don't zoom if targeting something other than the map itself
69027 if (_typeof(d3_event.target.__data__) === 'object' && // or area fills
69028 !select(d3_event.target).classed('fill')) return;
69029 var zoomOut = d3_event.shiftKey;
69030 var t = projection.transform();
69031 var p1 = t.invert(p0);
69032 t = t.scale(zoomOut ? 0.5 : 2);
69033 t.x = p0[0] - p1[0] * t.k;
69034 t.y = p0[1] - p1[1] * t.k;
69035 map.transformEase(t);
69038 context.on('enter.map', function () {
69039 if (!map.editableDataEnabled(true
69040 /* skip zoom check */
69042 if (_isTransformed) return; // redraw immediately any objects affected by a change in selectedIDs.
69044 var graph = context.graph();
69045 var selectedAndParents = {};
69046 context.selectedIDs().forEach(function (id) {
69047 var entity = graph.hasEntity(id);
69050 selectedAndParents[entity.id] = entity;
69052 if (entity.type === 'node') {
69053 graph.parentWays(entity).forEach(function (parent) {
69054 selectedAndParents[parent.id] = parent;
69059 var data = Object.values(selectedAndParents);
69061 var filter = function filter(d) {
69062 return d.id in selectedAndParents;
69065 data = context.features().filter(data, graph);
69066 surface.call(drawVertices.drawSelected, graph, map.extent()).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent());
69067 dispatch.call('drawn', this, {
69069 }); // redraw everything else later
69073 map.dimensions(utilGetDimensions(selection));
69076 function zoomEventFilter(d3_event) {
69077 // Fix for #2151, (see also d3/d3-zoom#60, d3/d3-brush#18)
69078 // Intercept `mousedown` and check if there is an orphaned zoom gesture.
69079 // This can happen if a previous `mousedown` occurred without a `mouseup`.
69080 // If we detect this, dispatch `mouseup` to complete the orphaned gesture,
69081 // so that d3-zoom won't stop propagation of new `mousedown` events.
69082 if (d3_event.type === 'mousedown') {
69083 var hasOrphan = false;
69084 var listeners = window.__on;
69086 for (var i = 0; i < listeners.length; i++) {
69087 var listener = listeners[i];
69089 if (listener.name === 'zoom' && listener.type === 'mouseup') {
69096 var event = window.CustomEvent;
69099 event = new event('mouseup');
69101 event = window.document.createEvent('Event');
69102 event.initEvent('mouseup', false, false);
69103 } // Event needs to be dispatched with an event.view property.
69106 event.view = window;
69107 window.dispatchEvent(event);
69111 return d3_event.button !== 2; // ignore right clicks
69114 function pxCenter() {
69115 return [_dimensions[0] / 2, _dimensions[1] / 2];
69118 function drawEditable(difference, extent) {
69119 var mode = context.mode();
69120 var graph = context.graph();
69121 var features = context.features();
69122 var all = context.history().intersects(map.extent());
69123 var fullRedraw = false;
69127 var applyFeatureLayerFilters = true;
69129 if (map.isInWideSelection()) {
69131 utilEntityAndDeepMemberIDs(mode.selectedIDs(), context.graph()).forEach(function (id) {
69132 var entity = context.hasEntity(id);
69133 if (entity) data.push(entity);
69136 filter = utilFunctor(true); // selected features should always be visible, so we can skip filtering
69138 applyFeatureLayerFilters = false;
69139 } else if (difference) {
69140 var complete = difference.complete(map.extent());
69141 data = Object.values(complete).filter(Boolean);
69142 set = new Set(Object.keys(complete));
69144 filter = function filter(d) {
69145 return set.has(d.id);
69148 features.clear(data);
69150 // force a full redraw if gatherStats detects that a feature
69151 // should be auto-hidden (e.g. points or buildings)..
69152 if (features.gatherStats(all, graph, _dimensions)) {
69153 extent = undefined;
69157 data = context.history().intersects(map.extent().intersection(extent));
69158 set = new Set(data.map(function (entity) {
69162 filter = function filter(d) {
69163 return set.has(d.id);
69168 filter = utilFunctor(true);
69172 if (applyFeatureLayerFilters) {
69173 data = features.filter(data, graph);
69175 context.features().resetStats();
69178 if (mode && mode.id === 'select') {
69179 // update selected vertices - the user might have just double-clicked a way,
69180 // creating a new vertex, triggering a partial redraw without a mode change
69181 surface.call(drawVertices.drawSelected, graph, map.extent());
69184 surface.call(drawVertices, graph, data, filter, map.extent(), fullRedraw).call(drawLines, graph, data, filter).call(drawAreas, graph, data, filter).call(drawMidpoints, graph, data, filter, map.trimmedExtent()).call(drawLabels, graph, data, filter, _dimensions, fullRedraw).call(drawPoints, graph, data, filter);
69185 dispatch.call('drawn', this, {
69190 map.init = function () {
69191 drawLayers = svgLayers(projection, context);
69192 drawPoints = svgPoints(projection, context);
69193 drawVertices = svgVertices(projection, context);
69194 drawLines = svgLines(projection, context);
69195 drawAreas = svgAreas(projection, context);
69196 drawMidpoints = svgMidpoints(projection, context);
69197 drawLabels = svgLabels(projection, context);
69200 function editOff() {
69201 context.features().resetStats();
69202 surface.selectAll('.layer-osm *').remove();
69203 surface.selectAll('.layer-touch:not(.markers) *').remove();
69207 'select-note': true,
69208 'select-data': true,
69209 'select-error': true
69211 var mode = context.mode();
69213 if (mode && !allowed[mode.id]) {
69214 context.enter(modeBrowse(context));
69217 dispatch.call('drawn', this, {
69222 function gestureChange(d3_event) {
69223 // Remap Safari gesture events to wheel events - #5492
69224 // We want these disabled most places, but enabled for zoom/unzoom on map surface
69225 // https://developer.mozilla.org/en-US/docs/Web/API/GestureEvent
69227 e.preventDefault();
69230 // dummy values to ignore in zoomPan
69232 // dummy values to ignore in zoomPan
69233 clientX: e.clientX,
69234 clientY: e.clientY,
69235 screenX: e.screenX,
69236 screenY: e.screenY,
69240 var e2 = new WheelEvent('wheel', props);
69241 e2._scale = e.scale; // preserve the original scale
69243 e2._rotation = e.rotation; // preserve the original rotation
69245 _selection.node().dispatchEvent(e2);
69248 function zoomPan(event, key, transform) {
69249 var source = event && event.sourceEvent || event;
69250 var eventTransform = transform || event && event.transform;
69251 var x = eventTransform.x;
69252 var y = eventTransform.y;
69253 var k = eventTransform.k; // Special handling of 'wheel' events:
69254 // They might be triggered by the user scrolling the mouse wheel,
69255 // or 2-finger pinch/zoom gestures, the transform may need adjustment.
69257 if (source && source.type === 'wheel') {
69258 // assume that the gesture is already handled by pointer events
69259 if (_pointerDown) return;
69260 var detected = utilDetect();
69261 var dX = source.deltaX;
69262 var dY = source.deltaY;
69266 var t0, p0, p1; // Normalize mousewheel scroll speed (Firefox) - #3029
69267 // If wheel delta is provided in LINE units, recalculate it in PIXEL units
69268 // We are essentially redoing the calculations that occur here:
69269 // https://github.com/d3/d3-zoom/blob/78563a8348aa4133b07cac92e2595c2227ca7cd7/src/zoom.js#L203
69270 // See this for more info:
69271 // https://github.com/basilfx/normalize-wheel/blob/master/src/normalizeWheel.js
69273 if (source.deltaMode === 1
69276 // Convert from lines to pixels, more if the user is scrolling fast.
69277 // (I made up the exp function to roughly match Firefox to what Chrome does)
69278 // These numbers should be floats, because integers are treated as pan gesture below.
69279 var lines = Math.abs(source.deltaY);
69280 var sign = source.deltaY > 0 ? 1 : -1;
69281 dY = sign * clamp$1(Math.exp((lines - 1) * 0.75) * 4.000244140625, 4.000244140625, // min
69282 350.000244140625 // max
69283 ); // On Firefox Windows and Linux we always get +/- the scroll line amount (default 3)
69284 // There doesn't seem to be any scroll acceleration.
69285 // This multiplier increases the speed a little bit - #5512
69287 if (detected.os !== 'mac') {
69289 } // recalculate x2,y2,k2
69292 t0 = _isTransformed ? _transformLast : _transformStart;
69293 p0 = _getMouseCoords(source);
69294 p1 = t0.invert(p0);
69295 k2 = t0.k * Math.pow(2, -dY / 500);
69296 k2 = clamp$1(k2, kMin, kMax);
69297 x2 = p0[0] - p1[0] * k2;
69298 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (Safari) - #5492
69299 // These are fake `wheel` events we made from Safari `gesturechange` events..
69300 } else if (source._scale) {
69301 // recalculate x2,y2,k2
69302 t0 = _gestureTransformStart;
69303 p0 = _getMouseCoords(source);
69304 p1 = t0.invert(p0);
69305 k2 = t0.k * source._scale;
69306 k2 = clamp$1(k2, kMin, kMax);
69307 x2 = p0[0] - p1[0] * k2;
69308 y2 = p0[1] - p1[1] * k2; // 2 finger map pinch zooming (all browsers except Safari) - #5492
69309 // Pinch zooming via the `wheel` event will always have:
69310 // - `ctrlKey = true`
69311 // - `deltaY` is not round integer pixels (ignore `deltaX`)
69312 } else if (source.ctrlKey && !isInteger(dY)) {
69313 dY *= 6; // slightly scale up whatever the browser gave us
69314 // recalculate x2,y2,k2
69316 t0 = _isTransformed ? _transformLast : _transformStart;
69317 p0 = _getMouseCoords(source);
69318 p1 = t0.invert(p0);
69319 k2 = t0.k * Math.pow(2, -dY / 500);
69320 k2 = clamp$1(k2, kMin, kMax);
69321 x2 = p0[0] - p1[0] * k2;
69322 y2 = p0[1] - p1[1] * k2; // Trackpad scroll zooming with shift or alt/option key down
69323 } else if ((source.altKey || source.shiftKey) && isInteger(dY)) {
69324 // recalculate x2,y2,k2
69325 t0 = _isTransformed ? _transformLast : _transformStart;
69326 p0 = _getMouseCoords(source);
69327 p1 = t0.invert(p0);
69328 k2 = t0.k * Math.pow(2, -dY / 500);
69329 k2 = clamp$1(k2, kMin, kMax);
69330 x2 = p0[0] - p1[0] * k2;
69331 y2 = p0[1] - p1[1] * k2; // 2 finger map panning (Mac only, all browsers except Firefox #8595) - #5492, #5512
69332 // Panning via the `wheel` event will always have:
69333 // - `ctrlKey = false`
69334 // - `deltaX`,`deltaY` are round integer pixels
69335 } else if (detected.os === 'mac' && detected.browser !== 'Firefox' && !source.ctrlKey && isInteger(dX) && isInteger(dY)) {
69336 p1 = projection.translate();
69339 k2 = projection.scale();
69340 k2 = clamp$1(k2, kMin, kMax);
69341 } // something changed - replace the event transform
69344 if (x2 !== x || y2 !== y || k2 !== k) {
69348 eventTransform = identity$2.translate(x2, y2).scale(k2);
69350 if (_zoomerPanner._transform) {
69351 // utilZoomPan interface
69352 _zoomerPanner._transform(eventTransform);
69354 // d3_zoom interface
69355 _selection.node().__zoom = eventTransform;
69360 if (_transformStart.x === x && _transformStart.y === y && _transformStart.k === k) {
69361 return; // no change
69364 if (geoScaleToZoom(k, TILESIZE) < _minzoom) {
69365 surface.interrupt();
69366 dispatch.call('hitMinZoom', this, map);
69367 setCenterZoom(map.center(), context.minEditableZoom(), 0, true);
69369 dispatch.call('move', this, map);
69373 projection.transform(eventTransform);
69374 var withinEditableZoom = map.withinEditableZoom();
69376 if (_lastWithinEditableZoom !== withinEditableZoom) {
69377 if (_lastWithinEditableZoom !== undefined) {
69378 // notify that the map zoomed in or out over the editable zoom threshold
69379 dispatch.call('crossEditableZoom', this, withinEditableZoom);
69382 _lastWithinEditableZoom = withinEditableZoom;
69385 var scale = k / _transformStart.k;
69386 var tX = (x / scale - _transformStart.x) * scale;
69387 var tY = (y / scale - _transformStart.y) * scale;
69389 if (context.inIntro()) {
69390 curtainProjection.transform({
69398 _lastPointerEvent = event;
69401 _isTransformed = true;
69402 _transformLast = eventTransform;
69403 utilSetTransform(supersurface, tX, tY, scale);
69405 dispatch.call('move', this, map);
69407 function isInteger(val) {
69408 return typeof val === 'number' && isFinite(val) && Math.floor(val) === val;
69412 function resetTransform() {
69413 if (!_isTransformed) return false;
69414 utilSetTransform(supersurface, 0, 0);
69415 _isTransformed = false;
69417 if (context.inIntro()) {
69418 curtainProjection.transform(projection.transform());
69424 function redraw(difference, extent) {
69425 if (surface.empty() || !_redrawEnabled) return; // If we are in the middle of a zoom/pan, we can't do differenced redraws.
69426 // It would result in artifacts where differenced entities are redrawn with
69427 // one transform and unchanged entities with another.
69429 if (resetTransform()) {
69430 difference = extent = undefined;
69433 var zoom = map.zoom();
69434 var z = String(~~zoom);
69436 if (surface.attr('data-zoom') !== z) {
69437 surface.attr('data-zoom', z);
69438 } // class surface as `lowzoom` around z17-z18.5 (based on latitude)
69441 var lat = map.center()[1];
69442 var lowzoom = linear().domain([-60, 0, 60]).range([17, 18.5, 17]).clamp(true);
69443 surface.classed('low-zoom', zoom <= lowzoom(lat));
69446 supersurface.call(context.background());
69447 wrapper.call(drawLayers);
69451 if (map.editableDataEnabled() || map.isInWideSelection()) {
69452 context.loadTiles(projection);
69453 drawEditable(difference, extent);
69458 _transformStart = projection.transform();
69462 var immediateRedraw = function immediateRedraw(difference, extent) {
69463 if (!difference && !extent) cancelPendingRedraw();
69464 redraw(difference, extent);
69467 map.lastPointerEvent = function () {
69468 return _lastPointerEvent;
69471 map.mouse = function (d3_event) {
69472 var event = d3_event || _lastPointerEvent;
69477 while (s = event.sourceEvent) {
69481 return _getMouseCoords(event);
69485 }; // returns Lng/Lat
69488 map.mouseCoordinates = function () {
69489 var coord = map.mouse() || pxCenter();
69490 return projection.invert(coord);
69493 map.dblclickZoomEnable = function (val) {
69494 if (!arguments.length) return _dblClickZoomEnabled;
69495 _dblClickZoomEnabled = val;
69499 map.redrawEnable = function (val) {
69500 if (!arguments.length) return _redrawEnabled;
69501 _redrawEnabled = val;
69505 map.isTransformed = function () {
69506 return _isTransformed;
69509 function setTransform(t2, duration, force) {
69510 var t = projection.transform();
69511 if (!force && t2.k === t.k && t2.x === t.x && t2.y === t.y) return false;
69514 _selection.transition().duration(duration).on('start', function () {
69516 }).call(_zoomerPanner.transform, identity$2.translate(t2.x, t2.y).scale(t2.k));
69518 projection.transform(t2);
69519 _transformStart = t2;
69521 _selection.call(_zoomerPanner.transform, _transformStart);
69527 function setCenterZoom(loc2, z2, duration, force) {
69528 var c = map.center();
69529 var z = map.zoom();
69530 if (loc2[0] === c[0] && loc2[1] === c[1] && z2 === z && !force) return false;
69531 var proj = geoRawMercator().transform(projection.transform()); // copy projection
69533 var k2 = clamp$1(geoZoomToScale(z2, TILESIZE), kMin, kMax);
69535 var t = proj.translate();
69536 var point = proj(loc2);
69537 var center = pxCenter();
69538 t[0] += center[0] - point[0];
69539 t[1] += center[1] - point[1];
69540 return setTransform(identity$2.translate(t[0], t[1]).scale(k2), duration, force);
69543 map.pan = function (delta, duration) {
69544 var t = projection.translate();
69545 var k = projection.scale();
69550 _selection.transition().duration(duration).on('start', function () {
69552 }).call(_zoomerPanner.transform, identity$2.translate(t[0], t[1]).scale(k));
69554 projection.translate(t);
69555 _transformStart = projection.transform();
69557 _selection.call(_zoomerPanner.transform, _transformStart);
69559 dispatch.call('move', this, map);
69566 map.dimensions = function (val) {
69567 if (!arguments.length) return _dimensions;
69569 drawLayers.dimensions(_dimensions);
69570 context.background().dimensions(_dimensions);
69571 projection.clipExtent([[0, 0], _dimensions]);
69572 _getMouseCoords = utilFastMouse(supersurface.node());
69577 function zoomIn(delta) {
69578 setCenterZoom(map.center(), ~~map.zoom() + delta, 250, true);
69581 function zoomOut(delta) {
69582 setCenterZoom(map.center(), ~~map.zoom() - delta, 250, true);
69585 map.zoomIn = function () {
69589 map.zoomInFurther = function () {
69593 map.canZoomIn = function () {
69594 return map.zoom() < maxZoom;
69597 map.zoomOut = function () {
69601 map.zoomOutFurther = function () {
69605 map.canZoomOut = function () {
69606 return map.zoom() > minZoom;
69609 map.center = function (loc2) {
69610 if (!arguments.length) {
69611 return projection.invert(pxCenter());
69614 if (setCenterZoom(loc2, map.zoom())) {
69615 dispatch.call('move', this, map);
69622 map.unobscuredCenterZoomEase = function (loc, zoom) {
69623 var offset = map.unobscuredOffsetPx();
69624 var proj = geoRawMercator().transform(projection.transform()); // copy projection
69625 // use the target zoom to calculate the offset center
69627 proj.scale(geoZoomToScale(zoom, TILESIZE));
69628 var locPx = proj(loc);
69629 var offsetLocPx = [locPx[0] + offset[0], locPx[1] + offset[1]];
69630 var offsetLoc = proj.invert(offsetLocPx);
69631 map.centerZoomEase(offsetLoc, zoom);
69634 map.unobscuredOffsetPx = function () {
69635 var openPane = context.container().select('.map-panes .map-pane.shown');
69637 if (!openPane.empty()) {
69638 return [openPane.node().offsetWidth / 2, 0];
69644 map.zoom = function (z2) {
69645 if (!arguments.length) {
69646 return Math.max(geoScaleToZoom(projection.scale(), TILESIZE), 0);
69649 if (z2 < _minzoom) {
69650 surface.interrupt();
69651 dispatch.call('hitMinZoom', this, map);
69652 z2 = context.minEditableZoom();
69655 if (setCenterZoom(map.center(), z2)) {
69656 dispatch.call('move', this, map);
69663 map.centerZoom = function (loc2, z2) {
69664 if (setCenterZoom(loc2, z2)) {
69665 dispatch.call('move', this, map);
69672 map.zoomTo = function (entity) {
69673 var extent = entity.extent(context.graph());
69674 if (!isFinite(extent.area())) return map;
69675 var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
69676 return map.centerZoom(extent.center(), z2);
69679 map.centerEase = function (loc2, duration) {
69680 duration = duration || 250;
69681 setCenterZoom(loc2, map.zoom(), duration);
69685 map.zoomEase = function (z2, duration) {
69686 duration = duration || 250;
69687 setCenterZoom(map.center(), z2, duration, false);
69691 map.centerZoomEase = function (loc2, z2, duration) {
69692 duration = duration || 250;
69693 setCenterZoom(loc2, z2, duration, false);
69697 map.transformEase = function (t2, duration) {
69698 duration = duration || 250;
69699 setTransform(t2, duration, false
69705 map.zoomToEase = function (obj, duration) {
69708 if (Array.isArray(obj)) {
69709 obj.forEach(function (entity) {
69710 var entityExtent = entity.extent(context.graph());
69713 extent = entityExtent;
69715 extent = extent.extend(entityExtent);
69719 extent = obj.extent(context.graph());
69722 if (!isFinite(extent.area())) return map;
69723 var z2 = clamp$1(map.trimmedExtentZoom(extent), 0, 20);
69724 return map.centerZoomEase(extent.center(), z2, duration);
69727 map.startEase = function () {
69728 utilBindOnce(surface, _pointerPrefix + 'down.ease', function () {
69734 map.cancelEase = function () {
69735 _selection.interrupt();
69740 map.extent = function (val) {
69741 if (!arguments.length) {
69742 return new geoExtent(projection.invert([0, _dimensions[1]]), projection.invert([_dimensions[0], 0]));
69744 var extent = geoExtent(val);
69745 map.centerZoom(extent.center(), map.extentZoom(extent));
69749 map.trimmedExtent = function (val) {
69750 if (!arguments.length) {
69754 return new geoExtent(projection.invert([pad, _dimensions[1] - footerY - pad]), projection.invert([_dimensions[0] - pad, headerY + pad]));
69756 var extent = geoExtent(val);
69757 map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
69761 function calcExtentZoom(extent, dim) {
69762 var tl = projection([extent[0][0], extent[1][1]]);
69763 var br = projection([extent[1][0], extent[0][1]]); // Calculate maximum zoom that fits extent
69765 var hFactor = (br[0] - tl[0]) / dim[0];
69766 var vFactor = (br[1] - tl[1]) / dim[1];
69767 var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
69768 var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
69769 var newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
69773 map.extentZoom = function (val) {
69774 return calcExtentZoom(geoExtent(val), _dimensions);
69777 map.trimmedExtentZoom = function (val) {
69780 var trimmed = [_dimensions[0] - trimX, _dimensions[1] - trimY];
69781 return calcExtentZoom(geoExtent(val), trimmed);
69784 map.withinEditableZoom = function () {
69785 return map.zoom() >= context.minEditableZoom();
69788 map.isInWideSelection = function () {
69789 return !map.withinEditableZoom() && context.selectedIDs().length;
69792 map.editableDataEnabled = function (skipZoomCheck) {
69793 var layer = context.layers().layer('osm');
69794 if (!layer || !layer.enabled()) return false;
69795 return skipZoomCheck || map.withinEditableZoom();
69798 map.notesEditable = function () {
69799 var layer = context.layers().layer('notes');
69800 if (!layer || !layer.enabled()) return false;
69801 return map.withinEditableZoom();
69804 map.minzoom = function (val) {
69805 if (!arguments.length) return _minzoom;
69810 map.toggleHighlightEdited = function () {
69811 surface.classed('highlight-edited', !surface.classed('highlight-edited'));
69812 map.pan([0, 0]); // trigger a redraw
69814 dispatch.call('changeHighlighting', this);
69817 map.areaFillOptions = ['wireframe', 'partial', 'full'];
69819 map.activeAreaFill = function (val) {
69820 if (!arguments.length) return corePreferences('area-fill') || 'partial';
69821 corePreferences('area-fill', val);
69823 if (val !== 'wireframe') {
69824 corePreferences('area-fill-toggle', val);
69828 map.pan([0, 0]); // trigger a redraw
69830 dispatch.call('changeAreaFill', this);
69834 map.toggleWireframe = function () {
69835 var activeFill = map.activeAreaFill();
69837 if (activeFill === 'wireframe') {
69838 activeFill = corePreferences('area-fill-toggle') || 'partial';
69840 activeFill = 'wireframe';
69843 map.activeAreaFill(activeFill);
69846 function updateAreaFill() {
69847 var activeFill = map.activeAreaFill();
69848 map.areaFillOptions.forEach(function (opt) {
69849 surface.classed('fill-' + opt, Boolean(opt === activeFill));
69853 map.layers = function () {
69857 map.doubleUpHandler = function () {
69858 return _doubleUpHandler;
69861 return utilRebind(map, dispatch, 'on');
69864 function rendererPhotos(context) {
69865 var dispatch = dispatch$8('change');
69866 var _layerIDs = ['streetside', 'mapillary', 'mapillary-map-features', 'mapillary-signs', 'openstreetcam'];
69867 var _allPhotoTypes = ['flat', 'panoramic'];
69869 var _shownPhotoTypes = _allPhotoTypes.slice(); // shallow copy
69872 var _dateFilters = ['fromDate', 'toDate'];
69880 function photos() {}
69882 function updateStorage() {
69883 if (window.mocha) return;
69884 var hash = utilStringQs(window.location.hash);
69885 var enabled = context.layers().all().filter(function (d) {
69886 return _layerIDs.indexOf(d.id) !== -1 && d.layer && d.layer.supported() && d.layer.enabled();
69887 }).map(function (d) {
69891 if (enabled.length) {
69892 hash.photo_overlay = enabled.join(',');
69894 delete hash.photo_overlay;
69897 window.location.replace('#' + utilQsString(hash, true));
69900 photos.overlayLayerIDs = function () {
69904 photos.allPhotoTypes = function () {
69905 return _allPhotoTypes;
69908 photos.dateFilters = function () {
69909 return _dateFilters;
69912 photos.dateFilterValue = function (val) {
69913 return val === _dateFilters[0] ? _fromDate : _toDate;
69916 photos.setDateFilter = function (type, val, updateUrl) {
69917 // validate the date
69918 var date = val && new Date(val);
69920 if (date && !isNaN(date)) {
69921 val = date.toISOString().substr(0, 10);
69926 if (type === _dateFilters[0]) {
69929 if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
69930 _toDate = _fromDate;
69934 if (type === _dateFilters[1]) {
69937 if (_fromDate && _toDate && new Date(_toDate) < new Date(_fromDate)) {
69938 _fromDate = _toDate;
69942 dispatch.call('change', this);
69947 if (_fromDate || _toDate) {
69948 rangeString = (_fromDate || '') + '_' + (_toDate || '');
69951 setUrlFilterValue('photo_dates', rangeString);
69955 photos.setUsernameFilter = function (val, updateUrl) {
69956 if (val && typeof val === 'string') val = val.replace(/;/g, ',').split(',');
69959 val = val.map(function (d) {
69961 }).filter(Boolean);
69969 dispatch.call('change', this);
69975 hashString = _usernames.join(',');
69978 setUrlFilterValue('photo_username', hashString);
69982 function setUrlFilterValue(property, val) {
69983 if (!window.mocha) {
69984 var hash = utilStringQs(window.location.hash);
69987 if (hash[property] === val) return;
69988 hash[property] = val;
69990 if (!(property in hash)) return;
69991 delete hash[property];
69994 window.location.replace('#' + utilQsString(hash, true));
69998 function showsLayer(id) {
69999 var layer = context.layers().layer(id);
70000 return layer && layer.supported() && layer.enabled();
70003 photos.shouldFilterByDate = function () {
70004 return showsLayer('mapillary') || showsLayer('openstreetcam') || showsLayer('streetside');
70007 photos.shouldFilterByPhotoType = function () {
70008 return showsLayer('mapillary') || showsLayer('streetside') && showsLayer('openstreetcam');
70011 photos.shouldFilterByUsername = function () {
70012 return !showsLayer('mapillary') && showsLayer('openstreetcam') && !showsLayer('streetside');
70015 photos.showsPhotoType = function (val) {
70016 if (!photos.shouldFilterByPhotoType()) return true;
70017 return _shownPhotoTypes.indexOf(val) !== -1;
70020 photos.showsFlat = function () {
70021 return photos.showsPhotoType('flat');
70024 photos.showsPanoramic = function () {
70025 return photos.showsPhotoType('panoramic');
70028 photos.fromDate = function () {
70032 photos.toDate = function () {
70036 photos.togglePhotoType = function (val) {
70037 var index = _shownPhotoTypes.indexOf(val);
70039 if (index !== -1) {
70040 _shownPhotoTypes.splice(index, 1);
70042 _shownPhotoTypes.push(val);
70045 dispatch.call('change', this);
70049 photos.usernames = function () {
70053 photos.init = function () {
70054 var hash = utilStringQs(window.location.hash);
70056 if (hash.photo_dates) {
70057 // expect format like `photo_dates=2019-01-01_2020-12-31`, but allow a couple different separators
70058 var parts = /^(.*)[–_](.*)$/g.exec(hash.photo_dates.trim());
70059 this.setDateFilter('fromDate', parts && parts.length >= 2 && parts[1], false);
70060 this.setDateFilter('toDate', parts && parts.length >= 3 && parts[2], false);
70063 if (hash.photo_username) {
70064 this.setUsernameFilter(hash.photo_username, false);
70067 if (hash.photo_overlay) {
70068 // support enabling photo layers by default via a URL parameter, e.g. `photo_overlay=openstreetcam;mapillary;streetside`
70069 var hashOverlayIDs = hash.photo_overlay.replace(/;/g, ',').split(',');
70070 hashOverlayIDs.forEach(function (id) {
70071 var layer = _layerIDs.indexOf(id) !== -1 && context.layers().layer(id);
70072 if (layer && !layer.enabled()) layer.enabled(true);
70077 // support opening a photo via a URL parameter, e.g. `photo=mapillary-fztgSDtLpa08ohPZFZjeRQ`
70078 var photoIds = hash.photo.replace(/;/g, ',').split(',');
70079 var photoId = photoIds.length && photoIds[0].trim();
70080 var results = /(.*)\/(.*)/g.exec(photoId);
70082 if (results && results.length >= 3) {
70083 var serviceId = results[1];
70084 var photoKey = results[2];
70085 var service = services[serviceId];
70087 if (service && service.ensureViewerLoaded) {
70088 // if we're showing a photo then make sure its layer is enabled too
70089 var layer = _layerIDs.indexOf(serviceId) !== -1 && context.layers().layer(serviceId);
70090 if (layer && !layer.enabled()) layer.enabled(true);
70091 var baselineTime = Date.now();
70092 service.on('loadedImages.rendererPhotos', function () {
70093 // don't open the viewer if too much time has elapsed
70094 if (Date.now() - baselineTime > 45000) {
70095 service.on('loadedImages.rendererPhotos', null);
70099 if (!service.cachedImage(photoKey)) return;
70100 service.on('loadedImages.rendererPhotos', null);
70101 service.ensureViewerLoaded(context).then(function () {
70102 service.selectImage(context, photoKey).showViewer(context);
70109 context.layers().on('change.rendererPhotos', updateStorage);
70112 return utilRebind(photos, dispatch, 'on');
70115 function uiAccount(context) {
70116 var osm = context.connection();
70118 function update(selection) {
70121 if (!osm.authenticated()) {
70122 selection.selectAll('.userLink, .logoutLink').classed('hide', true);
70126 osm.userDetails(function (err, details) {
70127 var userLink = selection.select('.userLink'),
70128 logoutLink = selection.select('.logoutLink');
70130 logoutLink.html('');
70131 if (err || !details) return;
70132 selection.selectAll('.userLink, .logoutLink').classed('hide', false); // Link
70134 var userLinkA = userLink.append('a').attr('href', osm.userURL(details.display_name)).attr('target', '_blank'); // Add thumbnail or dont
70136 if (details.image_url) {
70137 userLinkA.append('img').attr('class', 'icon pre-text user-icon').attr('src', details.image_url);
70139 userLinkA.call(svgIcon('#iD-icon-avatar', 'pre-text light'));
70143 userLinkA.append('span').attr('class', 'label').html(details.display_name);
70144 logoutLink.append('a').attr('class', 'logout').attr('href', '#').html(_t.html('logout')).on('click.logout', function (d3_event) {
70145 d3_event.preventDefault();
70151 return function (selection) {
70152 selection.append('li').attr('class', 'userLink').classed('hide', true);
70153 selection.append('li').attr('class', 'logoutLink').classed('hide', true);
70156 osm.on('change.account', function () {
70164 function uiAttribution(context) {
70165 var _selection = select(null);
70167 function render(selection, data, klass) {
70168 var div = selection.selectAll(".".concat(klass)).data([0]);
70169 div = div.enter().append('div').attr('class', klass).merge(div);
70170 var attributions = div.selectAll('.attribution').data(data, function (d) {
70173 attributions.exit().remove();
70174 attributions = attributions.enter().append('span').attr('class', 'attribution').each(function (d, i, nodes) {
70175 var attribution = select(nodes[i]);
70177 if (d.terms_html) {
70178 attribution.html(d.terms_html);
70183 attribution = attribution.append('a').attr('href', d.terms_url).attr('target', '_blank');
70186 var sourceID = d.id.replace(/\./g, '<TX_DOT>');
70187 var terms_text = _t("imagery.".concat(sourceID, ".attribution.text"), {
70188 "default": d.terms_text || d.id || d.name()
70191 if (d.icon && !d.overlay) {
70192 attribution.append('img').attr('class', 'source-image').attr('src', d.icon);
70195 attribution.append('span').attr('class', 'attribution-text').html(terms_text);
70196 }).merge(attributions);
70197 var copyright = attributions.selectAll('.copyright-notice').data(function (d) {
70198 var notice = d.copyrightNotices(context.map().zoom(), context.map().extent());
70199 return notice ? [notice] : [];
70201 copyright.exit().remove();
70202 copyright = copyright.enter().append('span').attr('class', 'copyright-notice').merge(copyright);
70203 copyright.html(String);
70206 function update() {
70207 var baselayer = context.background().baseLayerSource();
70209 _selection.call(render, baselayer ? [baselayer] : [], 'base-layer-attribution');
70211 var z = context.map().zoom();
70212 var overlays = context.background().overlayLayerSources() || [];
70214 _selection.call(render, overlays.filter(function (s) {
70215 return s.validZoom(z);
70216 }), 'overlay-layer-attribution');
70219 return function (selection) {
70220 _selection = selection;
70221 context.background().on('change.attribution', update);
70222 context.map().on('move.attribution', throttle(update, 400, {
70229 function uiContributors(context) {
70230 var osm = context.connection(),
70231 debouncedUpdate = debounce(function () {
70236 wrap = select(null);
70238 function update() {
70241 entities = context.history().intersects(context.map().extent());
70242 entities.forEach(function (entity) {
70243 if (entity && entity.user) users[entity.user] = true;
70245 var u = Object.keys(users),
70246 subset = u.slice(0, u.length > limit ? limit - 1 : limit);
70247 wrap.html('').call(svgIcon('#iD-icon-nearby', 'pre-text light'));
70248 var userList = select(document.createElement('span'));
70249 userList.selectAll().data(subset).enter().append('a').attr('class', 'user-link').attr('href', function (d) {
70250 return osm.userURL(d);
70251 }).attr('target', '_blank').html(String);
70253 if (u.length > limit) {
70254 var count = select(document.createElement('span'));
70255 var othersNum = u.length - limit + 1;
70256 count.append('a').attr('target', '_blank').attr('href', function () {
70257 return osm.changesetsURL(context.map().center(), context.map().zoom());
70258 }).html(othersNum);
70259 wrap.append('span').html(_t.html('contributors.truncated_list', {
70261 users: userList.html(),
70262 count: count.html()
70265 wrap.append('span').html(_t.html('contributors.list', {
70266 users: userList.html()
70272 wrap.transition().style('opacity', 0);
70273 } else if (hidden) {
70274 wrap.transition().style('opacity', 1);
70278 return function (selection) {
70282 osm.on('loaded.contributors', debouncedUpdate);
70283 context.map().on('move.contributors', debouncedUpdate);
70287 var _popoverID = 0;
70288 function uiPopover(klass) {
70289 var _id = _popoverID++;
70291 var _anchorSelection = select(null);
70293 var popover = function popover(selection) {
70294 _anchorSelection = selection;
70295 selection.each(setup);
70298 var _animation = utilFunctor(false);
70300 var _placement = utilFunctor('top'); // top, bottom, left, right
70303 var _alignment = utilFunctor('center'); // leading, center, trailing
70306 var _scrollContainer = utilFunctor(select(null));
70310 var _displayType = utilFunctor('');
70312 var _hasArrow = utilFunctor(true); // use pointer events on supported platforms; fallback to mouse events
70315 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
70317 popover.displayType = function (val) {
70318 if (arguments.length) {
70319 _displayType = utilFunctor(val);
70322 return _displayType;
70326 popover.hasArrow = function (val) {
70327 if (arguments.length) {
70328 _hasArrow = utilFunctor(val);
70335 popover.placement = function (val) {
70336 if (arguments.length) {
70337 _placement = utilFunctor(val);
70344 popover.alignment = function (val) {
70345 if (arguments.length) {
70346 _alignment = utilFunctor(val);
70353 popover.scrollContainer = function (val) {
70354 if (arguments.length) {
70355 _scrollContainer = utilFunctor(val);
70358 return _scrollContainer;
70362 popover.content = function (val) {
70363 if (arguments.length) {
70371 popover.isShown = function () {
70372 var popoverSelection = _anchorSelection.select('.popover-' + _id);
70374 return !popoverSelection.empty() && popoverSelection.classed('in');
70377 popover.show = function () {
70378 _anchorSelection.each(show);
70381 popover.updateContent = function () {
70382 _anchorSelection.each(updateContent);
70385 popover.hide = function () {
70386 _anchorSelection.each(hide);
70389 popover.toggle = function () {
70390 _anchorSelection.each(toggle);
70393 popover.destroy = function (selection, selector) {
70394 // by default, just destroy the current popover
70395 selector = selector || '.popover-' + _id;
70396 selection.on(_pointerPrefix + 'enter.popover', null).on(_pointerPrefix + 'leave.popover', null).on(_pointerPrefix + 'up.popover', null).on(_pointerPrefix + 'down.popover', null).on('click.popover', null).attr('title', function () {
70397 return this.getAttribute('data-original-title') || this.getAttribute('title');
70398 }).attr('data-original-title', null).selectAll(selector).remove();
70401 popover.destroyAny = function (selection) {
70402 selection.call(popover.destroy, '.popover');
70406 var anchor = select(this);
70408 var animate = _animation.apply(this, arguments);
70410 var popoverSelection = anchor.selectAll('.popover-' + _id).data([0]);
70411 var enter = popoverSelection.enter().append('div').attr('class', 'popover popover-' + _id + ' ' + (klass ? klass : '')).classed('arrowed', _hasArrow.apply(this, arguments));
70412 enter.append('div').attr('class', 'popover-arrow');
70413 enter.append('div').attr('class', 'popover-inner');
70414 popoverSelection = enter.merge(popoverSelection);
70417 popoverSelection.classed('fade', true);
70420 var display = _displayType.apply(this, arguments);
70422 if (display === 'hover') {
70423 var _lastNonMouseEnterTime;
70425 anchor.on(_pointerPrefix + 'enter.popover', function (d3_event) {
70426 if (d3_event.pointerType) {
70427 if (d3_event.pointerType !== 'mouse') {
70428 _lastNonMouseEnterTime = d3_event.timeStamp; // only allow hover behavior for mouse input
70431 } else if (_lastNonMouseEnterTime && d3_event.timeStamp - _lastNonMouseEnterTime < 1500) {
70432 // HACK: iOS 13.4 sends an erroneous `mouse` type pointerenter
70433 // event for non-mouse interactions right after sending
70434 // the correct type pointerenter event. Workaround by discarding
70435 // any mouse event that occurs immediately after a non-mouse event.
70438 } // don't show if buttons are pressed, e.g. during click and drag of map
70441 if (d3_event.buttons !== 0) return;
70442 show.apply(this, arguments);
70443 }).on(_pointerPrefix + 'leave.popover', function () {
70444 hide.apply(this, arguments);
70445 }) // show on focus too for better keyboard navigation support
70446 .on('focus.popover', function () {
70447 show.apply(this, arguments);
70448 }).on('blur.popover', function () {
70449 hide.apply(this, arguments);
70451 } else if (display === 'clickFocus') {
70452 anchor.on(_pointerPrefix + 'down.popover', function (d3_event) {
70453 d3_event.preventDefault();
70454 d3_event.stopPropagation();
70455 }).on(_pointerPrefix + 'up.popover', function (d3_event) {
70456 d3_event.preventDefault();
70457 d3_event.stopPropagation();
70458 }).on('click.popover', toggle);
70459 popoverSelection // This attribute lets the popover take focus
70460 .attr('tabindex', 0).on('blur.popover', function () {
70461 anchor.each(function () {
70462 hide.apply(this, arguments);
70469 var anchor = select(this);
70470 var popoverSelection = anchor.selectAll('.popover-' + _id);
70472 if (popoverSelection.empty()) {
70473 // popover was removed somehow, put it back
70474 anchor.call(popover.destroy);
70475 anchor.each(setup);
70476 popoverSelection = anchor.selectAll('.popover-' + _id);
70479 popoverSelection.classed('in', true);
70481 var displayType = _displayType.apply(this, arguments);
70483 if (displayType === 'clickFocus') {
70484 anchor.classed('active', true);
70485 popoverSelection.node().focus();
70488 anchor.each(updateContent);
70491 function updateContent() {
70492 var anchor = select(this);
70495 anchor.selectAll('.popover-' + _id + ' > .popover-inner').call(_content.apply(this, arguments));
70498 updatePosition.apply(this, arguments); // hack: update multiple times to fix instances where the absolute offset is
70499 // set before the dynamic popover size is calculated by the browser
70501 updatePosition.apply(this, arguments);
70502 updatePosition.apply(this, arguments);
70505 function updatePosition() {
70506 var anchor = select(this);
70507 var popoverSelection = anchor.selectAll('.popover-' + _id);
70509 var scrollContainer = _scrollContainer && _scrollContainer.apply(this, arguments);
70511 var scrollNode = scrollContainer && !scrollContainer.empty() && scrollContainer.node();
70512 var scrollLeft = scrollNode ? scrollNode.scrollLeft : 0;
70513 var scrollTop = scrollNode ? scrollNode.scrollTop : 0;
70515 var placement = _placement.apply(this, arguments);
70517 popoverSelection.classed('left', false).classed('right', false).classed('top', false).classed('bottom', false).classed(placement, true);
70519 var alignment = _alignment.apply(this, arguments);
70521 var alignFactor = 0.5;
70523 if (alignment === 'leading') {
70525 } else if (alignment === 'trailing') {
70529 var anchorFrame = getFrame(anchor.node());
70530 var popoverFrame = getFrame(popoverSelection.node());
70533 switch (placement) {
70536 x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
70537 y: anchorFrame.y - popoverFrame.h
70543 x: anchorFrame.x + (anchorFrame.w - popoverFrame.w) * alignFactor,
70544 y: anchorFrame.y + anchorFrame.h
70550 x: anchorFrame.x - popoverFrame.w,
70551 y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
70557 x: anchorFrame.x + anchorFrame.w,
70558 y: anchorFrame.y + (anchorFrame.h - popoverFrame.h) * alignFactor
70564 if (scrollNode && (placement === 'top' || placement === 'bottom')) {
70565 var initialPosX = position.x;
70567 if (position.x + popoverFrame.w > scrollNode.offsetWidth - 10) {
70568 position.x = scrollNode.offsetWidth - 10 - popoverFrame.w;
70569 } else if (position.x < 10) {
70573 var arrow = anchor.selectAll('.popover-' + _id + ' > .popover-arrow'); // keep the arrow centered on the button, or as close as possible
70575 var arrowPosX = Math.min(Math.max(popoverFrame.w / 2 - (position.x - initialPosX), 10), popoverFrame.w - 10);
70576 arrow.style('left', ~~arrowPosX + 'px');
70579 popoverSelection.style('left', ~~position.x + 'px').style('top', ~~position.y + 'px');
70581 popoverSelection.style('left', null).style('top', null);
70584 function getFrame(node) {
70585 var positionStyle = select(node).style('position');
70587 if (positionStyle === 'absolute' || positionStyle === 'static') {
70589 x: node.offsetLeft - scrollLeft,
70590 y: node.offsetTop - scrollTop,
70591 w: node.offsetWidth,
70592 h: node.offsetHeight
70598 w: node.offsetWidth,
70599 h: node.offsetHeight
70606 var anchor = select(this);
70608 if (_displayType.apply(this, arguments) === 'clickFocus') {
70609 anchor.classed('active', false);
70612 anchor.selectAll('.popover-' + _id).classed('in', false);
70615 function toggle() {
70616 if (select(this).select('.popover-' + _id).classed('in')) {
70617 hide.apply(this, arguments);
70619 show.apply(this, arguments);
70626 function uiTooltip(klass) {
70627 var tooltip = uiPopover((klass || '') + ' tooltip').displayType('hover');
70629 var _title = function _title() {
70630 var title = this.getAttribute('data-original-title');
70635 title = this.getAttribute('title');
70636 this.removeAttribute('title');
70637 this.setAttribute('data-original-title', title);
70643 var _heading = utilFunctor(null);
70645 var _keys = utilFunctor(null);
70647 tooltip.title = function (val) {
70648 if (!arguments.length) return _title;
70649 _title = utilFunctor(val);
70653 tooltip.heading = function (val) {
70654 if (!arguments.length) return _heading;
70655 _heading = utilFunctor(val);
70659 tooltip.keys = function (val) {
70660 if (!arguments.length) return _keys;
70661 _keys = utilFunctor(val);
70665 tooltip.content(function () {
70666 var heading = _heading.apply(this, arguments);
70668 var text = _title.apply(this, arguments);
70670 var keys = _keys.apply(this, arguments);
70672 return function (selection) {
70673 var headingSelect = selection.selectAll('.tooltip-heading').data(heading ? [heading] : []);
70674 headingSelect.exit().remove();
70675 headingSelect.enter().append('div').attr('class', 'tooltip-heading').merge(headingSelect).html(heading);
70676 var textSelect = selection.selectAll('.tooltip-text').data(text ? [text] : []);
70677 textSelect.exit().remove();
70678 textSelect.enter().append('div').attr('class', 'tooltip-text').merge(textSelect).html(text);
70679 var keyhintWrap = selection.selectAll('.keyhint-wrap').data(keys && keys.length ? [0] : []);
70680 keyhintWrap.exit().remove();
70681 var keyhintWrapEnter = keyhintWrap.enter().append('div').attr('class', 'keyhint-wrap');
70682 keyhintWrapEnter.append('span').html(_t.html('tooltip_keyhint'));
70683 keyhintWrap = keyhintWrapEnter.merge(keyhintWrap);
70684 keyhintWrap.selectAll('kbd.shortcut').data(keys && keys.length ? keys : []).enter().append('kbd').attr('class', 'shortcut').html(function (d) {
70692 function uiEditMenu(context) {
70693 var dispatch = dispatch$8('toggled');
70695 var _menu = select(null);
70697 var _operations = []; // the position the menu should be displayed relative to
70699 var _anchorLoc = [0, 0];
70700 var _anchorLocLonLat = [0, 0]; // a string indicating how the menu was opened
70702 var _triggerType = '';
70703 var _vpTopMargin = 85; // viewport top margin
70705 var _vpBottomMargin = 45; // viewport bottom margin
70707 var _vpSideMargin = 35; // viewport side margin
70709 var _menuTop = false;
70713 var _menuWidth; // hardcode these values to make menu positioning easier
70716 var _verticalPadding = 4; // see also `.edit-menu .tooltip` CSS; include margin
70718 var _tooltipWidth = 210; // offset the menu slightly from the target location
70720 var _menuSideMargin = 10;
70721 var _tooltips = [];
70723 var editMenu = function editMenu(selection) {
70724 var isTouchMenu = _triggerType.includes('touch') || _triggerType.includes('pen');
70726 var ops = _operations.filter(function (op) {
70727 return !isTouchMenu || !op.mouseOnly;
70730 if (!ops.length) return;
70731 _tooltips = []; // Position the menu above the anchor for stylus and finger input
70732 // since the mapper's hand likely obscures the screen below the anchor
70734 _menuTop = isTouchMenu; // Show labels for touch input since there aren't hover tooltips
70736 var showLabels = isTouchMenu;
70737 var buttonHeight = showLabels ? 32 : 34;
70740 // Get a general idea of the width based on the length of the label
70741 _menuWidth = 52 + Math.min(120, 6 * Math.max.apply(Math, ops.map(function (op) {
70742 return op.title.length;
70748 _menuHeight = _verticalPadding * 2 + ops.length * buttonHeight;
70749 _menu = selection.append('div').attr('class', 'edit-menu').classed('touch-menu', isTouchMenu).style('padding', _verticalPadding + 'px 0');
70751 var buttons = _menu.selectAll('.edit-menu-item').data(ops); // enter
70754 var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
70755 return 'edit-menu-item edit-menu-item-' + d.id;
70756 }).style('height', buttonHeight + 'px').on('click', click) // don't listen for `mouseup` because we only care about non-mouse pointer types
70757 .on('pointerup', pointerup).on('pointerdown mousedown', function pointerdown(d3_event) {
70758 // don't let button presses also act as map input - #1869
70759 d3_event.stopPropagation();
70760 }).on('mouseenter.highlight', function (d3_event, d) {
70761 if (!d.relatedEntityIds || select(this).classed('disabled')) return;
70762 utilHighlightEntities(d.relatedEntityIds(), true, context);
70763 }).on('mouseleave.highlight', function (d3_event, d) {
70764 if (!d.relatedEntityIds) return;
70765 utilHighlightEntities(d.relatedEntityIds(), false, context);
70767 buttonsEnter.each(function (d) {
70768 var tooltip = uiTooltip().heading(d.title).title(d.tooltip()).keys([d.keys[0]]);
70770 _tooltips.push(tooltip);
70772 select(this).call(tooltip).append('div').attr('class', 'icon-wrap').call(svgIcon('#iD-operation-' + d.id, 'operation'));
70776 buttonsEnter.append('span').attr('class', 'label').html(function (d) {
70782 buttonsEnter.merge(buttons).classed('disabled', function (d) {
70783 return d.disabled();
70786 var initialScale = context.projection.scale();
70787 context.map().on('move.edit-menu', function () {
70788 if (initialScale !== context.projection.scale()) {
70791 }).on('drawn.edit-menu', function (info) {
70792 if (info.full) updatePosition();
70794 var lastPointerUpType; // `pointerup` is always called before `click`
70796 function pointerup(d3_event) {
70797 lastPointerUpType = d3_event.pointerType;
70800 function click(d3_event, operation) {
70801 d3_event.stopPropagation();
70803 if (operation.relatedEntityIds) {
70804 utilHighlightEntities(operation.relatedEntityIds(), false, context);
70807 if (operation.disabled()) {
70808 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
70809 // there are no tooltips for touch interactions so flash feedback instead
70810 context.ui().flash.duration(4000).iconName('#iD-operation-' + operation.id).iconClass('operation disabled').label(operation.tooltip)();
70813 if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
70814 context.ui().flash.duration(2000).iconName('#iD-operation-' + operation.id).iconClass('operation').label(operation.annotation() || operation.title)();
70821 lastPointerUpType = null;
70824 dispatch.call('toggled', this, true);
70827 function updatePosition() {
70828 if (!_menu || _menu.empty()) return;
70829 var anchorLoc = context.projection(_anchorLocLonLat);
70830 var viewport = context.surfaceRect();
70832 if (anchorLoc[0] < 0 || anchorLoc[0] > viewport.width || anchorLoc[1] < 0 || anchorLoc[1] > viewport.height) {
70833 // close the menu if it's gone offscreen
70838 var menuLeft = displayOnLeft(viewport);
70839 var offset = [0, 0];
70840 offset[0] = menuLeft ? -1 * (_menuSideMargin + _menuWidth) : _menuSideMargin;
70843 if (anchorLoc[1] - _menuHeight < _vpTopMargin) {
70844 // menu is near top viewport edge, shift downward
70845 offset[1] = -anchorLoc[1] + _vpTopMargin;
70847 offset[1] = -_menuHeight;
70850 if (anchorLoc[1] + _menuHeight > viewport.height - _vpBottomMargin) {
70851 // menu is near bottom viewport edge, shift upwards
70852 offset[1] = -anchorLoc[1] - _menuHeight + viewport.height - _vpBottomMargin;
70858 var origin = geoVecAdd(anchorLoc, offset);
70860 _menu.style('left', origin[0] + 'px').style('top', origin[1] + 'px');
70862 var tooltipSide = tooltipPosition(viewport, menuLeft);
70864 _tooltips.forEach(function (tooltip) {
70865 tooltip.placement(tooltipSide);
70868 function displayOnLeft(viewport) {
70869 if (_mainLocalizer.textDirection() === 'ltr') {
70870 if (anchorLoc[0] + _menuSideMargin + _menuWidth > viewport.width - _vpSideMargin) {
70871 // right menu would be too close to the right viewport edge, go left
70873 } // prefer right menu
70879 if (anchorLoc[0] - _menuSideMargin - _menuWidth < _vpSideMargin) {
70880 // left menu would be too close to the left viewport edge, go right
70882 } // prefer left menu
70889 function tooltipPosition(viewport, menuLeft) {
70890 if (_mainLocalizer.textDirection() === 'ltr') {
70892 // if there's not room for a right-side menu then there definitely
70893 // isn't room for right-side tooltips
70897 if (anchorLoc[0] + _menuSideMargin + _menuWidth + _tooltipWidth > viewport.width - _vpSideMargin) {
70898 // right tooltips would be too close to the right viewport edge, go left
70900 } // prefer right tooltips
70910 if (anchorLoc[0] - _menuSideMargin - _menuWidth - _tooltipWidth < _vpSideMargin) {
70911 // left tooltips would be too close to the left viewport edge, go right
70913 } // prefer left tooltips
70921 editMenu.close = function () {
70922 context.map().on('move.edit-menu', null).on('drawn.edit-menu', null);
70927 dispatch.call('toggled', this, false);
70930 editMenu.anchorLoc = function (val) {
70931 if (!arguments.length) return _anchorLoc;
70933 _anchorLocLonLat = context.projection.invert(_anchorLoc);
70937 editMenu.triggerType = function (val) {
70938 if (!arguments.length) return _triggerType;
70939 _triggerType = val;
70943 editMenu.operations = function (val) {
70944 if (!arguments.length) return _operations;
70949 return utilRebind(editMenu, dispatch, 'on');
70952 function uiFeatureInfo(context) {
70953 function update(selection) {
70954 var features = context.features();
70955 var stats = features.stats();
70957 var hiddenList = features.hidden().map(function (k) {
70960 return _t('inspector.title_count', {
70961 title: _t.html('feature.' + k + '.description'),
70967 }).filter(Boolean);
70968 selection.html('');
70970 if (hiddenList.length) {
70971 var tooltipBehavior = uiTooltip().placement('top').title(function () {
70972 return hiddenList.join('<br/>');
70974 selection.append('a').attr('class', 'chip').attr('href', '#').html(_t.html('feature_info.hidden_warning', {
70976 })).call(tooltipBehavior).on('click', function (d3_event) {
70977 tooltipBehavior.hide();
70978 d3_event.preventDefault(); // open the Map Data pane
70980 context.ui().togglePanes(context.container().select('.map-panes .map-data-pane'));
70984 selection.classed('hide', !hiddenList.length);
70987 return function (selection) {
70989 context.features().on('change.feature_info', function () {
70995 function uiFlash(context) {
70998 var _duration = 2000;
70999 var _iconName = '#iD-icon-no';
71000 var _iconClass = 'disabled';
71005 _flashTimer.stop();
71008 context.container().select('.main-footer-wrap').classed('footer-hide', true).classed('footer-show', false);
71009 context.container().select('.flash-wrap').classed('footer-hide', false).classed('footer-show', true);
71010 var content = context.container().select('.flash-wrap').selectAll('.flash-content').data([0]); // Enter
71012 var contentEnter = content.enter().append('div').attr('class', 'flash-content');
71013 var iconEnter = contentEnter.append('svg').attr('class', 'flash-icon icon').append('g').attr('transform', 'translate(10,10)');
71014 iconEnter.append('circle').attr('r', 9);
71015 iconEnter.append('use').attr('transform', 'translate(-7,-7)').attr('width', '14').attr('height', '14');
71016 contentEnter.append('div').attr('class', 'flash-text'); // Update
71018 content = content.merge(contentEnter);
71019 content.selectAll('.flash-icon').attr('class', 'icon flash-icon ' + (_iconClass || ''));
71020 content.selectAll('.flash-icon use').attr('xlink:href', _iconName);
71021 content.selectAll('.flash-text').attr('class', 'flash-text').html(_label);
71022 _flashTimer = d3_timeout(function () {
71023 _flashTimer = null;
71024 context.container().select('.main-footer-wrap').classed('footer-hide', false).classed('footer-show', true);
71025 context.container().select('.flash-wrap').classed('footer-hide', true).classed('footer-show', false);
71030 flash.duration = function (_) {
71031 if (!arguments.length) return _duration;
71036 flash.label = function (_) {
71037 if (!arguments.length) return _label;
71042 flash.iconName = function (_) {
71043 if (!arguments.length) return _iconName;
71048 flash.iconClass = function (_) {
71049 if (!arguments.length) return _iconClass;
71057 function uiFullScreen(context) {
71058 var element = context.container().node(); // var button = d3_select(null);
71060 function getFullScreenFn() {
71061 if (element.requestFullscreen) {
71062 return element.requestFullscreen;
71063 } else if (element.msRequestFullscreen) {
71064 return element.msRequestFullscreen;
71065 } else if (element.mozRequestFullScreen) {
71066 return element.mozRequestFullScreen;
71067 } else if (element.webkitRequestFullscreen) {
71068 return element.webkitRequestFullscreen;
71072 function getExitFullScreenFn() {
71073 if (document.exitFullscreen) {
71074 return document.exitFullscreen;
71075 } else if (document.msExitFullscreen) {
71076 return document.msExitFullscreen;
71077 } else if (document.mozCancelFullScreen) {
71078 return document.mozCancelFullScreen;
71079 } else if (document.webkitExitFullscreen) {
71080 return document.webkitExitFullscreen;
71084 function isFullScreen() {
71085 return document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
71088 function isSupported() {
71089 return !!getFullScreenFn();
71092 function fullScreen(d3_event) {
71093 d3_event.preventDefault();
71095 if (!isFullScreen()) {
71096 // button.classed('active', true);
71097 getFullScreenFn().apply(element);
71099 // button.classed('active', false);
71100 getExitFullScreenFn().apply(document);
71104 return function () {
71106 if (!isSupported()) return; // button = selection.append('button')
71107 // .attr('title', t('full_screen'))
71108 // .on('click', fullScreen)
71110 // button.append('span')
71111 // .attr('class', 'icon full-screen');
71113 var detected = utilDetect();
71114 var keys = detected.os === 'mac' ? [uiCmd('⌃⌘F'), 'f11'] : ['f11'];
71115 context.keybinding().on(keys, fullScreen);
71119 function uiGeolocate(context) {
71120 var _geolocationOptions = {
71121 // prioritize speed and power usage over precision
71122 enableHighAccuracy: false,
71123 // don't hang indefinitely getting the location
71124 timeout: 6000 // 6sec
71128 var _locating = uiLoading(context).message(_t.html('geolocate.locating')).blocking(true);
71130 var _layer = context.layers().layer('geolocate');
71138 var _button = select(null);
71141 if (context.inIntro()) return;
71143 if (!_layer.enabled() && !_locating.isShown()) {
71144 // This timeout ensures that we still call finish() even if
71145 // the user declines to share their location in Firefox
71146 _timeoutID = setTimeout(error, 10000
71149 context.container().call(_locating); // get the latest position even if we already have one
71151 navigator.geolocation.getCurrentPosition(success, error, _geolocationOptions);
71155 _layer.enabled(null, false);
71157 updateButtonState();
71161 function zoomTo() {
71162 context.enter(modeBrowse(context));
71163 var map = context.map();
71165 _layer.enabled(_position, true);
71167 updateButtonState();
71168 map.centerZoomEase(_extent.center(), Math.min(20, map.extentZoom(_extent)));
71171 function success(geolocation) {
71172 _position = geolocation;
71173 var coords = _position.coords;
71174 _extent = geoExtent([coords.longitude, coords.latitude]).padByMeters(coords.accuracy);
71181 // use the position from a previous call if we have one
71184 context.ui().flash.label(_t.html('geolocate.location_unavailable')).iconName('#iD-icon-geolocate')();
71190 function finish() {
71191 _locating.close(); // unblock ui
71195 clearTimeout(_timeoutID);
71198 _timeoutID = undefined;
71201 function updateButtonState() {
71202 _button.classed('active', _layer.enabled());
71205 return function (selection) {
71206 if (!navigator.geolocation || !navigator.geolocation.getCurrentPosition) return;
71207 _button = selection.append('button').on('click', click).call(svgIcon('#iD-icon-geolocate', 'light')).call(uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_t.html('geolocate.title')).keys([_t('geolocate.key')]));
71208 context.keybinding().on(_t('geolocate.key'), click);
71212 function uiPanelBackground(context) {
71213 var background = context.background();
71214 var _currSourceName = null;
71215 var _metadata = {};
71216 var _metadataKeys = ['zoom', 'vintage', 'source', 'description', 'resolution', 'accuracy'];
71218 var debouncedRedraw = debounce(redraw, 250);
71220 function redraw(selection) {
71221 var source = background.baseLayerSource();
71222 if (!source) return;
71223 var isDG = source.id.match(/^DigitalGlobe/i) !== null;
71224 var sourceLabel = source.label();
71226 if (_currSourceName !== sourceLabel) {
71227 _currSourceName = sourceLabel;
71231 selection.html('');
71232 var list = selection.append('ul').attr('class', 'background-info');
71233 list.append('li').html(_currSourceName);
71235 _metadataKeys.forEach(function (k) {
71236 // DigitalGlobe vintage is available in raster layers for now.
71237 if (isDG && k === 'vintage') return;
71238 list.append('li').attr('class', 'background-info-list-' + k).classed('hide', !_metadata[k]).html(_t.html('info_panels.background.' + k) + ':').append('span').attr('class', 'background-info-span-' + k).html(_metadata[k]);
71241 debouncedGetMetadata(selection);
71242 var toggleTiles = context.getDebug('tile') ? 'hide_tiles' : 'show_tiles';
71243 selection.append('a').html(_t.html('info_panels.background.' + toggleTiles)).attr('href', '#').attr('class', 'button button-toggle-tiles').on('click', function (d3_event) {
71244 d3_event.preventDefault();
71245 context.setDebug('tile', !context.getDebug('tile'));
71246 selection.call(redraw);
71250 var key = source.id + '-vintage';
71251 var sourceVintage = context.background().findSource(key);
71252 var showsVintage = context.background().showsLayer(sourceVintage);
71253 var toggleVintage = showsVintage ? 'hide_vintage' : 'show_vintage';
71254 selection.append('a').html(_t.html('info_panels.background.' + toggleVintage)).attr('href', '#').attr('class', 'button button-toggle-vintage').on('click', function (d3_event) {
71255 d3_event.preventDefault();
71256 context.background().toggleOverlayLayer(sourceVintage);
71257 selection.call(redraw);
71259 } // disable if necessary
71262 ['DigitalGlobe-Premium', 'DigitalGlobe-Standard'].forEach(function (layerId) {
71263 if (source.id !== layerId) {
71264 var key = layerId + '-vintage';
71265 var sourceVintage = context.background().findSource(key);
71267 if (context.background().showsLayer(sourceVintage)) {
71268 context.background().toggleOverlayLayer(sourceVintage);
71274 var debouncedGetMetadata = debounce(getMetadata, 250);
71276 function getMetadata(selection) {
71277 var tile = context.container().select('.layer-background img.tile-center'); // tile near viewport center
71279 if (tile.empty()) return;
71280 var sourceName = _currSourceName;
71281 var d = tile.datum();
71282 var zoom = d && d.length >= 3 && d[2] || Math.floor(context.map().zoom());
71283 var center = context.map().center(); // update zoom
71285 _metadata.zoom = String(zoom);
71286 selection.selectAll('.background-info-list-zoom').classed('hide', false).selectAll('.background-info-span-zoom').html(_metadata.zoom);
71287 if (!d || !d.length >= 3) return;
71288 background.baseLayerSource().getMetadata(center, d, function (err, result) {
71289 if (err || _currSourceName !== sourceName) return; // update vintage
71291 var vintage = result.vintage;
71292 _metadata.vintage = vintage && vintage.range || _t('info_panels.background.unknown');
71293 selection.selectAll('.background-info-list-vintage').classed('hide', false).selectAll('.background-info-span-vintage').html(_metadata.vintage); // update other _metadata
71295 _metadataKeys.forEach(function (k) {
71296 if (k === 'zoom' || k === 'vintage') return; // done already
71298 var val = result[k];
71299 _metadata[k] = val;
71300 selection.selectAll('.background-info-list-' + k).classed('hide', !val).selectAll('.background-info-span-' + k).html(val);
71305 var panel = function panel(selection) {
71306 selection.call(redraw);
71307 context.map().on('drawn.info-background', function () {
71308 selection.call(debouncedRedraw);
71309 }).on('move.info-background', function () {
71310 selection.call(debouncedGetMetadata);
71314 panel.off = function () {
71315 context.map().on('drawn.info-background', null).on('move.info-background', null);
71318 panel.id = 'background';
71319 panel.label = _t.html('info_panels.background.title');
71320 panel.key = _t('info_panels.background.key');
71324 function uiPanelHistory(context) {
71327 function displayTimestamp(timestamp) {
71328 if (!timestamp) return _t('info_panels.history.unknown');
71337 var d = new Date(timestamp);
71338 if (isNaN(d.getTime())) return _t('info_panels.history.unknown');
71339 return d.toLocaleString(_mainLocalizer.localeCode(), options);
71342 function displayUser(selection, userName) {
71344 selection.append('span').html(_t.html('info_panels.history.unknown'));
71348 selection.append('span').attr('class', 'user-name').html(userName);
71349 var links = selection.append('div').attr('class', 'links');
71352 links.append('a').attr('class', 'user-osm-link').attr('href', osm.userURL(userName)).attr('target', '_blank').html('OSM');
71355 links.append('a').attr('class', 'user-hdyc-link').attr('href', 'https://hdyc.neis-one.org/?' + userName).attr('target', '_blank').attr('tabindex', -1).html('HDYC');
71358 function displayChangeset(selection, changeset) {
71360 selection.append('span').html(_t.html('info_panels.history.unknown'));
71364 selection.append('span').attr('class', 'changeset-id').html(changeset);
71365 var links = selection.append('div').attr('class', 'links');
71368 links.append('a').attr('class', 'changeset-osm-link').attr('href', osm.changesetURL(changeset)).attr('target', '_blank').html('OSM');
71371 links.append('a').attr('class', 'changeset-osmcha-link').attr('href', 'https://osmcha.org/changesets/' + changeset).attr('target', '_blank').html('OSMCha');
71372 links.append('a').attr('class', 'changeset-achavi-link').attr('href', 'https://overpass-api.de/achavi/?changeset=' + changeset).attr('target', '_blank').html('Achavi');
71375 function redraw(selection) {
71376 var selectedNoteID = context.selectedNoteID();
71377 osm = context.connection();
71378 var selected, note, entity;
71380 if (selectedNoteID && osm) {
71382 selected = [_t('note.note') + ' ' + selectedNoteID];
71383 note = osm.getNote(selectedNoteID);
71385 // selected 1..n entities
71386 selected = context.selectedIDs().filter(function (e) {
71387 return context.hasEntity(e);
71390 if (selected.length) {
71391 entity = context.entity(selected[0]);
71395 var singular = selected.length === 1 ? selected[0] : null;
71396 selection.html('');
71397 selection.append('h4').attr('class', 'history-heading').html(singular || _t.html('info_panels.selected', {
71400 if (!singular) return;
71403 selection.call(redrawEntity, entity);
71405 selection.call(redrawNote, note);
71409 function redrawNote(selection, note) {
71410 if (!note || note.isNew()) {
71411 selection.append('div').html(_t.html('info_panels.history.note_no_history'));
71415 var list = selection.append('ul');
71416 list.append('li').html(_t.html('info_panels.history.note_comments') + ':').append('span').html(note.comments.length);
71418 if (note.comments.length) {
71419 list.append('li').html(_t.html('info_panels.history.note_created_date') + ':').append('span').html(displayTimestamp(note.comments[0].date));
71420 list.append('li').html(_t.html('info_panels.history.note_created_user') + ':').call(displayUser, note.comments[0].user);
71424 selection.append('a').attr('class', 'view-history-on-osm').attr('target', '_blank').attr('href', osm.noteURL(note)).call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html('info_panels.history.note_link_text'));
71428 function redrawEntity(selection, entity) {
71429 if (!entity || entity.isNew()) {
71430 selection.append('div').html(_t.html('info_panels.history.no_history'));
71434 var links = selection.append('div').attr('class', 'links');
71437 links.append('a').attr('class', 'view-history-on-osm').attr('href', osm.historyURL(entity)).attr('target', '_blank').attr('title', _t('info_panels.history.link_text')).html('OSM');
71440 links.append('a').attr('class', 'pewu-history-viewer-link').attr('href', 'https://pewu.github.io/osm-history/#/' + entity.type + '/' + entity.osmId()).attr('target', '_blank').attr('tabindex', -1).html('PeWu');
71441 var list = selection.append('ul');
71442 list.append('li').html(_t.html('info_panels.history.version') + ':').append('span').html(entity.version);
71443 list.append('li').html(_t.html('info_panels.history.last_edit') + ':').append('span').html(displayTimestamp(entity.timestamp));
71444 list.append('li').html(_t.html('info_panels.history.edited_by') + ':').call(displayUser, entity.user);
71445 list.append('li').html(_t.html('info_panels.history.changeset') + ':').call(displayChangeset, entity.changeset);
71448 var panel = function panel(selection) {
71449 selection.call(redraw);
71450 context.map().on('drawn.info-history', function () {
71451 selection.call(redraw);
71453 context.on('enter.info-history', function () {
71454 selection.call(redraw);
71458 panel.off = function () {
71459 context.map().on('drawn.info-history', null);
71460 context.on('enter.info-history', null);
71463 panel.id = 'history';
71464 panel.label = _t.html('info_panels.history.title');
71465 panel.key = _t('info_panels.history.key');
71469 var OSM_PRECISION = 7;
71471 * Returns a localized representation of the given length measurement.
71473 * @param {Number} m area in meters
71474 * @param {Boolean} isImperial true for U.S. customary units; false for metric
71477 function displayLength(m, isImperial) {
71478 var d = m * (isImperial ? 3.28084 : 1);
71491 unit = 'kilometers';
71497 return _t('units.' + unit, {
71498 quantity: d.toLocaleString(_mainLocalizer.localeCode(), {
71499 maximumSignificantDigits: 4
71504 * Returns a localized representation of the given area measurement.
71506 * @param {Number} m2 area in square meters
71507 * @param {Boolean} isImperial true for U.S. customary units; false for metric
71510 function displayArea(m2, isImperial) {
71511 var locale = _mainLocalizer.localeCode();
71512 var d = m2 * (isImperial ? 10.7639111056 : 1);
71518 if (d >= 6969600) {
71519 // > 0.25mi² show mi²
71521 unit1 = 'square_miles';
71524 unit1 = 'square_feet';
71527 if (d > 4356 && d < 43560000) {
71528 // 0.1 - 1000 acres
71534 // > 0.25km² show km²
71536 unit1 = 'square_kilometers';
71539 unit1 = 'square_meters';
71542 if (d > 1000 && d < 10000000) {
71543 // 0.1 - 1000 hectares
71545 unit2 = 'hectares';
71549 area = _t('units.' + unit1, {
71550 quantity: d1.toLocaleString(locale, {
71551 maximumSignificantDigits: 4
71556 return _t('units.area_pair', {
71558 area2: _t('units.' + unit2, {
71559 quantity: d2.toLocaleString(locale, {
71560 maximumSignificantDigits: 2
71569 function wrap(x, min, max) {
71571 return ((x - min) % d + d) % d + min;
71574 function clamp(x, min, max) {
71575 return Math.max(min, Math.min(x, max));
71578 function displayCoordinate(deg, pos, neg) {
71579 var locale = _mainLocalizer.localeCode();
71580 var min = (Math.abs(deg) - Math.floor(Math.abs(deg))) * 60;
71581 var sec = (min - Math.floor(min)) * 60;
71582 var displayDegrees = _t('units.arcdegrees', {
71583 quantity: Math.floor(Math.abs(deg)).toLocaleString(locale)
71585 var displayCoordinate;
71587 if (Math.floor(sec) > 0) {
71588 displayCoordinate = displayDegrees + _t('units.arcminutes', {
71589 quantity: Math.floor(min).toLocaleString(locale)
71590 }) + _t('units.arcseconds', {
71591 quantity: Math.round(sec).toLocaleString(locale)
71593 } else if (Math.floor(min) > 0) {
71594 displayCoordinate = displayDegrees + _t('units.arcminutes', {
71595 quantity: Math.round(min).toLocaleString(locale)
71598 displayCoordinate = _t('units.arcdegrees', {
71599 quantity: Math.round(Math.abs(deg)).toLocaleString(locale)
71604 return displayCoordinate;
71606 return _t('units.coordinate', {
71607 coordinate: displayCoordinate,
71608 direction: _t('units.' + (deg > 0 ? pos : neg))
71613 * Returns given coordinate pair in degree-minute-second format.
71615 * @param {Array<Number>} coord longitude and latitude
71619 function dmsCoordinatePair(coord) {
71620 return _t('units.coordinate_pair', {
71621 latitude: displayCoordinate(clamp(coord[1], -90, 90), 'north', 'south'),
71622 longitude: displayCoordinate(wrap(coord[0], -180, 180), 'east', 'west')
71626 * Returns the given coordinate pair in decimal format.
71627 * note: unlocalized to avoid comma ambiguity - see #4765
71629 * @param {Array<Number>} coord longitude and latitude
71632 function decimalCoordinatePair(coord) {
71633 return _t('units.coordinate_pair', {
71634 latitude: clamp(coord[1], -90, 90).toFixed(OSM_PRECISION),
71635 longitude: wrap(coord[0], -180, 180).toFixed(OSM_PRECISION)
71639 function uiPanelLocation(context) {
71640 var currLocation = '';
71642 function redraw(selection) {
71643 selection.html('');
71644 var list = selection.append('ul'); // Mouse coordinates
71646 var coord = context.map().mouseCoordinates();
71648 if (coord.some(isNaN)) {
71649 coord = context.map().center();
71652 list.append('li').html(dmsCoordinatePair(coord)).append('li').html(decimalCoordinatePair(coord)); // Location Info
71654 selection.append('div').attr('class', 'location-info').html(currLocation || ' ');
71655 debouncedGetLocation(selection, coord);
71658 var debouncedGetLocation = debounce(getLocation, 250);
71660 function getLocation(selection, coord) {
71661 if (!services.geocoder) {
71662 currLocation = _t('info_panels.location.unknown_location');
71663 selection.selectAll('.location-info').html(currLocation);
71665 services.geocoder.reverse(coord, function (err, result) {
71666 currLocation = result ? result.display_name : _t('info_panels.location.unknown_location');
71667 selection.selectAll('.location-info').html(currLocation);
71672 var panel = function panel(selection) {
71673 selection.call(redraw);
71674 context.surface().on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'move.info-location', function () {
71675 selection.call(redraw);
71679 panel.off = function () {
71680 context.surface().on('.info-location', null);
71683 panel.id = 'location';
71684 panel.label = _t.html('info_panels.location.title');
71685 panel.key = _t('info_panels.location.key');
71689 function uiPanelMeasurement(context) {
71690 function radiansToMeters(r) {
71691 // using WGS84 authalic radius (6371007.1809 m)
71692 return r * 6371007.1809;
71695 function steradiansToSqmeters(r) {
71696 // http://gis.stackexchange.com/a/124857/40446
71697 return r / (4 * Math.PI) * 510065621724000;
71700 function toLineString(feature) {
71701 if (feature.type === 'LineString') return feature;
71703 type: 'LineString',
71707 if (feature.type === 'Polygon') {
71708 result.coordinates = feature.coordinates[0];
71709 } else if (feature.type === 'MultiPolygon') {
71710 result.coordinates = feature.coordinates[0][0];
71716 var _isImperial = !_mainLocalizer.usesMetric();
71718 function redraw(selection) {
71719 var graph = context.graph();
71720 var selectedNoteID = context.selectedNoteID();
71721 var osm = services.osm;
71722 var localeCode = _mainLocalizer.localeCode();
71724 var center, location, centroid;
71725 var closed, geometry;
71726 var totalNodeCount,
71731 if (selectedNoteID && osm) {
71733 var note = osm.getNote(selectedNoteID);
71734 heading = _t('note.note') + ' ' + selectedNoteID;
71735 location = note.loc;
71738 // selected 1..n entities
71739 var selectedIDs = context.selectedIDs().filter(function (id) {
71740 return context.hasEntity(id);
71742 var selected = selectedIDs.map(function (id) {
71743 return context.entity(id);
71745 heading = selected.length === 1 ? selected[0].id : _t('info_panels.selected', {
71749 if (selected.length) {
71750 var extent = geoExtent();
71752 for (var i in selected) {
71753 var entity = selected[i];
71755 extent._extend(entity.extent(graph));
71757 geometry = entity.geometry(graph);
71759 if (geometry === 'line' || geometry === 'area') {
71760 closed = entity.type === 'relation' || entity.isClosed() && !entity.isDegenerate();
71761 var feature = entity.asGeoJSON(graph);
71762 length += radiansToMeters(d3_geoLength(toLineString(feature)));
71763 centroid = d3_geoPath(context.projection).centroid(entity.asGeoJSON(graph));
71764 centroid = centroid && context.projection.invert(centroid);
71766 if (!centroid || !isFinite(centroid[0]) || !isFinite(centroid[1])) {
71767 centroid = entity.extent(graph).center();
71771 area += steradiansToSqmeters(entity.area(graph));
71776 if (selected.length > 1) {
71782 if (selected.length === 2 && selected[0].type === 'node' && selected[1].type === 'node') {
71783 distance = geoSphericalDistance(selected[0].loc, selected[1].loc);
71786 if (selected.length === 1 && selected[0].type === 'node') {
71787 location = selected[0].loc;
71789 totalNodeCount = utilGetAllNodes(selectedIDs, context.graph()).length;
71792 if (!location && !centroid) {
71793 center = extent.center();
71798 selection.html('');
71801 selection.append('h4').attr('class', 'measurement-heading').html(heading);
71804 var list = selection.append('ul');
71808 list.append('li').html(_t.html('info_panels.measurement.geometry') + ':').append('span').html(closed ? _t('info_panels.measurement.closed_' + geometry) : _t('geometry.' + geometry));
71811 if (totalNodeCount) {
71812 list.append('li').html(_t.html('info_panels.measurement.node_count') + ':').append('span').html(totalNodeCount.toLocaleString(localeCode));
71816 list.append('li').html(_t.html('info_panels.measurement.area') + ':').append('span').html(displayArea(area, _isImperial));
71820 list.append('li').html(_t.html('info_panels.measurement.' + (closed ? 'perimeter' : 'length')) + ':').append('span').html(displayLength(length, _isImperial));
71823 if (typeof distance === 'number') {
71824 list.append('li').html(_t.html('info_panels.measurement.distance') + ':').append('span').html(displayLength(distance, _isImperial));
71828 coordItem = list.append('li').html(_t.html('info_panels.measurement.location') + ':');
71829 coordItem.append('span').html(dmsCoordinatePair(location));
71830 coordItem.append('span').html(decimalCoordinatePair(location));
71834 coordItem = list.append('li').html(_t.html('info_panels.measurement.centroid') + ':');
71835 coordItem.append('span').html(dmsCoordinatePair(centroid));
71836 coordItem.append('span').html(decimalCoordinatePair(centroid));
71840 coordItem = list.append('li').html(_t.html('info_panels.measurement.center') + ':');
71841 coordItem.append('span').html(dmsCoordinatePair(center));
71842 coordItem.append('span').html(decimalCoordinatePair(center));
71845 if (length || area || typeof distance === 'number') {
71846 var toggle = _isImperial ? 'imperial' : 'metric';
71847 selection.append('a').html(_t.html('info_panels.measurement.' + toggle)).attr('href', '#').attr('class', 'button button-toggle-units').on('click', function (d3_event) {
71848 d3_event.preventDefault();
71849 _isImperial = !_isImperial;
71850 selection.call(redraw);
71855 var panel = function panel(selection) {
71856 selection.call(redraw);
71857 context.map().on('drawn.info-measurement', function () {
71858 selection.call(redraw);
71860 context.on('enter.info-measurement', function () {
71861 selection.call(redraw);
71865 panel.off = function () {
71866 context.map().on('drawn.info-measurement', null);
71867 context.on('enter.info-measurement', null);
71870 panel.id = 'measurement';
71871 panel.label = _t.html('info_panels.measurement.title');
71872 panel.key = _t('info_panels.measurement.key');
71876 var uiInfoPanels = {
71877 background: uiPanelBackground,
71878 history: uiPanelHistory,
71879 location: uiPanelLocation,
71880 measurement: uiPanelMeasurement
71883 function uiInfo(context) {
71884 var ids = Object.keys(uiInfoPanels);
71885 var wasActive = ['measurement'];
71887 var active = {}; // create panels
71889 ids.forEach(function (k) {
71891 panels[k] = uiInfoPanels[k](context);
71896 function info(selection) {
71897 function redraw() {
71898 var activeids = ids.filter(function (k) {
71901 var containers = infoPanels.selectAll('.panel-container').data(activeids, function (k) {
71904 containers.exit().style('opacity', 1).transition().duration(200).style('opacity', 0).on('end', function (d) {
71905 select(this).call(panels[d].off).remove();
71907 var enter = containers.enter().append('div').attr('class', function (d) {
71908 return 'fillD2 panel-container panel-container-' + d;
71910 enter.style('opacity', 0).transition().duration(200).style('opacity', 1);
71911 var title = enter.append('div').attr('class', 'panel-title fillD2');
71912 title.append('h3').html(function (d) {
71913 return panels[d].label;
71915 title.append('button').attr('class', 'close').on('click', function (d3_event, d) {
71916 d3_event.stopImmediatePropagation();
71917 d3_event.preventDefault();
71919 }).call(svgIcon('#iD-icon-close'));
71920 enter.append('div').attr('class', function (d) {
71921 return 'panel-content panel-content-' + d;
71922 }); // redraw the panels
71924 infoPanels.selectAll('.panel-content').each(function (d) {
71925 select(this).call(panels[d]);
71929 info.toggle = function (which) {
71930 var activeids = ids.filter(function (k) {
71936 active[which] = !active[which];
71938 if (activeids.length === 1 && activeids[0] === which) {
71939 // none active anymore
71940 wasActive = [which];
71943 context.container().select('.' + which + '-panel-toggle-item').classed('active', active[which]).select('input').property('checked', active[which]);
71946 if (activeids.length) {
71947 wasActive = activeids;
71948 activeids.forEach(function (k) {
71952 wasActive.forEach(function (k) {
71961 var infoPanels = selection.selectAll('.info-panels').data([0]);
71962 infoPanels = infoPanels.enter().append('div').attr('class', 'info-panels').merge(infoPanels);
71964 context.keybinding().on(uiCmd('⌘' + _t('info_panels.key')), function (d3_event) {
71965 d3_event.stopImmediatePropagation();
71966 d3_event.preventDefault();
71969 ids.forEach(function (k) {
71970 var key = _t('info_panels.' + k + '.key', {
71974 context.keybinding().on(uiCmd('⌘⇧' + key), function (d3_event) {
71975 d3_event.stopImmediatePropagation();
71976 d3_event.preventDefault();
71985 function pointBox(loc, context) {
71986 var rect = context.surfaceRect();
71987 var point = context.curtainProjection(loc);
71989 left: point[0] + rect.left - 40,
71990 top: point[1] + rect.top - 60,
71995 function pad(locOrBox, padding, context) {
71998 if (locOrBox instanceof Array) {
71999 var rect = context.surfaceRect();
72000 var point = context.curtainProjection(locOrBox);
72002 left: point[0] + rect.left,
72003 top: point[1] + rect.top
72010 left: box.left - padding,
72011 top: box.top - padding,
72012 width: (box.width || 0) + 2 * padding,
72013 height: (box.width || 0) + 2 * padding
72016 function icon(name, svgklass, useklass) {
72017 return '<svg class="icon ' + (svgklass || '') + '">' + '<use xlink:href="' + name + '"' + (useklass ? ' class="' + useklass + '"' : '') + '></use></svg>';
72019 var helpStringReplacements; // Returns the localized HTML element for `id` with a standardized set of icon, key, and
72020 // label replacements suitable for tutorials and documentation. Optionally supplemented
72021 // with custom `replacements`
72023 function helpHtml(id, replacements) {
72024 // only load these the first time
72025 if (!helpStringReplacements) {
72026 helpStringReplacements = {
72027 // insert icons corresponding to various UI elements
72028 point_icon: icon('#iD-icon-point', 'inline'),
72029 line_icon: icon('#iD-icon-line', 'inline'),
72030 area_icon: icon('#iD-icon-area', 'inline'),
72031 note_icon: icon('#iD-icon-note', 'inline add-note'),
72032 plus: icon('#iD-icon-plus', 'inline'),
72033 minus: icon('#iD-icon-minus', 'inline'),
72034 layers_icon: icon('#iD-icon-layers', 'inline'),
72035 data_icon: icon('#iD-icon-data', 'inline'),
72036 inspect: icon('#iD-icon-inspect', 'inline'),
72037 help_icon: icon('#iD-icon-help', 'inline'),
72038 undo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo', 'inline'),
72039 redo_icon: icon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-undo' : '#iD-icon-redo', 'inline'),
72040 save_icon: icon('#iD-icon-save', 'inline'),
72042 circularize_icon: icon('#iD-operation-circularize', 'inline operation'),
72043 continue_icon: icon('#iD-operation-continue', 'inline operation'),
72044 copy_icon: icon('#iD-operation-copy', 'inline operation'),
72045 delete_icon: icon('#iD-operation-delete', 'inline operation'),
72046 disconnect_icon: icon('#iD-operation-disconnect', 'inline operation'),
72047 downgrade_icon: icon('#iD-operation-downgrade', 'inline operation'),
72048 extract_icon: icon('#iD-operation-extract', 'inline operation'),
72049 merge_icon: icon('#iD-operation-merge', 'inline operation'),
72050 move_icon: icon('#iD-operation-move', 'inline operation'),
72051 orthogonalize_icon: icon('#iD-operation-orthogonalize', 'inline operation'),
72052 paste_icon: icon('#iD-operation-paste', 'inline operation'),
72053 reflect_long_icon: icon('#iD-operation-reflect-long', 'inline operation'),
72054 reflect_short_icon: icon('#iD-operation-reflect-short', 'inline operation'),
72055 reverse_icon: icon('#iD-operation-reverse', 'inline operation'),
72056 rotate_icon: icon('#iD-operation-rotate', 'inline operation'),
72057 split_icon: icon('#iD-operation-split', 'inline operation'),
72058 straighten_icon: icon('#iD-operation-straighten', 'inline operation'),
72059 // interaction icons
72060 leftclick: icon('#iD-walkthrough-mouse-left', 'inline operation'),
72061 rightclick: icon('#iD-walkthrough-mouse-right', 'inline operation'),
72062 mousewheel_icon: icon('#iD-walkthrough-mousewheel', 'inline operation'),
72063 tap_icon: icon('#iD-walkthrough-tap', 'inline operation'),
72064 doubletap_icon: icon('#iD-walkthrough-doubletap', 'inline operation'),
72065 longpress_icon: icon('#iD-walkthrough-longpress', 'inline operation'),
72066 touchdrag_icon: icon('#iD-walkthrough-touchdrag', 'inline operation'),
72067 pinch_icon: icon('#iD-walkthrough-pinch-apart', 'inline operation'),
72068 // insert keys; may be localized and platform-dependent
72069 shift: uiCmd.display('⇧'),
72070 alt: uiCmd.display('⌥'),
72071 "return": uiCmd.display('↵'),
72072 esc: _t.html('shortcuts.key.esc'),
72073 space: _t.html('shortcuts.key.space'),
72074 add_note_key: _t.html('modes.add_note.key'),
72075 help_key: _t.html('help.key'),
72076 shortcuts_key: _t.html('shortcuts.toggle.key'),
72077 // reference localized UI labels directly so that they'll always match
72078 save: _t.html('save.title'),
72079 undo: _t.html('undo.title'),
72080 redo: _t.html('redo.title'),
72081 upload: _t.html('commit.save'),
72082 point: _t.html('modes.add_point.title'),
72083 line: _t.html('modes.add_line.title'),
72084 area: _t.html('modes.add_area.title'),
72085 note: _t.html('modes.add_note.label'),
72086 circularize: _t.html('operations.circularize.title'),
72087 "continue": _t.html('operations.continue.title'),
72088 copy: _t.html('operations.copy.title'),
72089 "delete": _t.html('operations.delete.title'),
72090 disconnect: _t.html('operations.disconnect.title'),
72091 downgrade: _t.html('operations.downgrade.title'),
72092 extract: _t.html('operations.extract.title'),
72093 merge: _t.html('operations.merge.title'),
72094 move: _t.html('operations.move.title'),
72095 orthogonalize: _t.html('operations.orthogonalize.title'),
72096 paste: _t.html('operations.paste.title'),
72097 reflect_long: _t.html('operations.reflect.title.long'),
72098 reflect_short: _t.html('operations.reflect.title.short'),
72099 reverse: _t.html('operations.reverse.title'),
72100 rotate: _t.html('operations.rotate.title'),
72101 split: _t.html('operations.split.title'),
72102 straighten: _t.html('operations.straighten.title'),
72103 map_data: _t.html('map_data.title'),
72104 osm_notes: _t.html('map_data.layers.notes.title'),
72105 fields: _t.html('inspector.fields'),
72106 tags: _t.html('inspector.tags'),
72107 relations: _t.html('inspector.relations'),
72108 new_relation: _t.html('inspector.new_relation'),
72109 turn_restrictions: _t.html('_tagging.presets.fields.restrictions.label'),
72110 background_settings: _t.html('background.description'),
72111 imagery_offset: _t.html('background.fix_misalignment'),
72112 start_the_walkthrough: _t.html('splash.walkthrough'),
72113 help: _t.html('help.title'),
72114 ok: _t.html('intro.ok')
72120 if (replacements) {
72121 reps = Object.assign(replacements, helpStringReplacements);
72123 reps = helpStringReplacements;
72126 return _t.html(id, reps) // use keyboard key styling for shortcuts
72127 .replace(/\`(.*?)\`/g, '<kbd>$1</kbd>');
72130 function slugify(text) {
72131 return text.toString().toLowerCase().replace(/\s+/g, '-') // Replace spaces with -
72132 .replace(/[^\w\-]+/g, '') // Remove all non-word chars
72133 .replace(/\-\-+/g, '-') // Replace multiple - with single -
72134 .replace(/^-+/, '') // Trim - from start of text
72135 .replace(/-+$/, ''); // Trim - from end of text
72136 } // console warning for missing walkthrough names
72139 var missingStrings = {};
72141 function checkKey(key, text) {
72143 "default": undefined
72144 }) === undefined) {
72145 if (missingStrings.hasOwnProperty(key)) return; // warn once
72147 missingStrings[key] = text;
72148 var missing = key + ': ' + text;
72149 if (typeof console !== 'undefined') console.log(missing); // eslint-disable-line
72153 function localize(obj) {
72154 var key; // Assign name if entity has one..
72156 var name = obj.tags && obj.tags.name;
72159 key = 'intro.graph.name.' + slugify(name);
72160 obj.tags.name = _t(key, {
72163 checkKey(key, name);
72164 } // Assign street name if entity has one..
72167 var street = obj.tags && obj.tags['addr:street'];
72170 key = 'intro.graph.name.' + slugify(street);
72171 obj.tags['addr:street'] = _t(key, {
72174 checkKey(key, street); // Add address details common across walkthrough..
72176 var addrTags = ['block_number', 'city', 'county', 'district', 'hamlet', 'neighbourhood', 'postcode', 'province', 'quarter', 'state', 'subdistrict', 'suburb'];
72177 addrTags.forEach(function (k) {
72178 var key = 'intro.graph.' + k;
72179 var tag = 'addr:' + k;
72180 var val = obj.tags && obj.tags[tag];
72181 var str = _t(key, {
72186 if (str.match(/^<.*>$/) !== null) {
72187 delete obj.tags[tag];
72189 obj.tags[tag] = str;
72196 } // Used to detect squareness.. some duplicataion of code from actionOrthogonalize.
72198 function isMostlySquare(points) {
72199 // note: uses 15 here instead of the 12 from actionOrthogonalize because
72200 // actionOrthogonalize can actually straighten some larger angles as it iterates
72201 var threshold = 15; // degrees within right or straight
72203 var lowerBound = Math.cos((90 - threshold) * Math.PI / 180); // near right
72205 var upperBound = Math.cos(threshold * Math.PI / 180); // near straight
72207 for (var i = 0; i < points.length; i++) {
72208 var a = points[(i - 1 + points.length) % points.length];
72209 var origin = points[i];
72210 var b = points[(i + 1) % points.length];
72211 var dotp = geoVecNormalizedDot(a, b, origin);
72212 var mag = Math.abs(dotp);
72214 if (mag > lowerBound && mag < upperBound) {
72221 function selectMenuItem(context, operation) {
72222 return context.container().select('.edit-menu .edit-menu-item-' + operation);
72224 function transitionTime(point1, point2) {
72225 var distance = geoSphericalDistance(point1, point2);
72227 if (distance === 0) {
72229 } else if (distance < 80) {
72236 // hide class, which sets display=none, and a d3 transition for opacity.
72237 // this will cause blinking when called repeatedly, so check that the
72238 // value actually changes between calls.
72240 function uiToggle(show, callback) {
72241 return function (selection) {
72242 selection.style('opacity', show ? 0 : 1).classed('hide', false).transition().style('opacity', show ? 1 : 0).on('end', function () {
72243 select(this).classed('hide', !show).style('opacity', null);
72244 if (callback) callback.apply(this);
72249 function uiCurtain(containerNode) {
72250 var surface = select(null),
72251 tooltip = select(null),
72252 darkness = select(null);
72254 function curtain(selection) {
72255 surface = selection.append('svg').attr('class', 'curtain').style('top', 0).style('left', 0);
72256 darkness = surface.append('path').attr('x', 0).attr('y', 0).attr('class', 'curtain-darkness');
72257 select(window).on('resize.curtain', resize);
72258 tooltip = selection.append('div').attr('class', 'tooltip');
72259 tooltip.append('div').attr('class', 'popover-arrow');
72260 tooltip.append('div').attr('class', 'popover-inner');
72263 function resize() {
72264 surface.attr('width', containerNode.clientWidth).attr('height', containerNode.clientHeight);
72265 curtain.cut(darkness.datum());
72269 * Reveal cuts the curtain to highlight the given box,
72270 * and shows a tooltip with instructions next to the box.
72272 * @param {String|ClientRect} [box] box used to cut the curtain
72273 * @param {String} [text] text for a tooltip
72274 * @param {Object} [options]
72275 * @param {string} [options.tooltipClass] optional class to add to the tooltip
72276 * @param {integer} [options.duration] transition time in milliseconds
72277 * @param {string} [options.buttonText] if set, create a button with this text label
72278 * @param {function} [options.buttonCallback] if set, the callback for the button
72279 * @param {function} [options.padding] extra margin in px to put around bbox
72280 * @param {String|ClientRect} [options.tooltipBox] box for tooltip position, if different from box for the curtain
72284 curtain.reveal = function (box, html, options) {
72285 options = options || {};
72287 if (typeof box === 'string') {
72288 box = select(box).node();
72291 if (box && box.getBoundingClientRect) {
72292 box = copyBox(box.getBoundingClientRect());
72293 var containerRect = containerNode.getBoundingClientRect();
72294 box.top -= containerRect.top;
72295 box.left -= containerRect.left;
72298 if (box && options.padding) {
72299 box.top -= options.padding;
72300 box.left -= options.padding;
72301 box.bottom += options.padding;
72302 box.right += options.padding;
72303 box.height += options.padding * 2;
72304 box.width += options.padding * 2;
72309 if (options.tooltipBox) {
72310 tooltipBox = options.tooltipBox;
72312 if (typeof tooltipBox === 'string') {
72313 tooltipBox = select(tooltipBox).node();
72316 if (tooltipBox && tooltipBox.getBoundingClientRect) {
72317 tooltipBox = copyBox(tooltipBox.getBoundingClientRect());
72323 if (tooltipBox && html) {
72324 if (html.indexOf('**') !== -1) {
72325 if (html.indexOf('<span') === 0) {
72326 html = html.replace(/^(<span.*?>)(.+?)(\*\*)/, '$1<span>$2</span>$3');
72328 html = html.replace(/^(.+?)(\*\*)/, '<span>$1</span>$2');
72329 } // pseudo markdown bold text for the instruction section..
72332 html = html.replace(/\*\*(.*?)\*\*/g, '<span class="instruction">$1</span>');
72335 html = html.replace(/\*(.*?)\*/g, '<em>$1</em>'); // emphasis
72337 html = html.replace(/\{br\}/g, '<br/><br/>'); // linebreak
72339 if (options.buttonText && options.buttonCallback) {
72340 html += '<div class="button-section">' + '<button href="#" class="button action">' + options.buttonText + '</button></div>';
72343 var classes = 'curtain-tooltip popover tooltip arrowed in ' + (options.tooltipClass || '');
72344 tooltip.classed(classes, true).selectAll('.popover-inner').html(html);
72346 if (options.buttonText && options.buttonCallback) {
72347 var button = tooltip.selectAll('.button-section .button.action');
72348 button.on('click', function (d3_event) {
72349 d3_event.preventDefault();
72350 options.buttonCallback();
72354 var tip = copyBox(tooltip.node().getBoundingClientRect()),
72355 w = containerNode.clientWidth,
72356 h = containerNode.clientHeight,
72357 tooltipWidth = 200,
72360 pos; // hack: this will have bottom placement,
72361 // so need to reserve extra space for the tooltip illustration.
72363 if (options.tooltipClass === 'intro-mouse') {
72365 } // trim box dimensions to just the portion that fits in the container..
72368 if (tooltipBox.top + tooltipBox.height > h) {
72369 tooltipBox.height -= tooltipBox.top + tooltipBox.height - h;
72372 if (tooltipBox.left + tooltipBox.width > w) {
72373 tooltipBox.width -= tooltipBox.left + tooltipBox.width - w;
72374 } // determine tooltip placement..
72377 if (tooltipBox.top + tooltipBox.height < 100) {
72378 // tooltip below box..
72380 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top + tooltipBox.height];
72381 } else if (tooltipBox.top > h - 140) {
72382 // tooltip above box..
72384 pos = [tooltipBox.left + tooltipBox.width / 2 - tip.width / 2, tooltipBox.top - tip.height];
72386 // tooltip to the side of the tooltipBox..
72387 var tipY = tooltipBox.top + tooltipBox.height / 2 - tip.height / 2;
72389 if (_mainLocalizer.textDirection() === 'rtl') {
72390 if (tooltipBox.left - tooltipWidth - tooltipArrow < 70) {
72392 pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
72395 pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
72398 if (tooltipBox.left + tooltipBox.width + tooltipArrow + tooltipWidth > w - 70) {
72400 pos = [tooltipBox.left - tooltipWidth - tooltipArrow, tipY];
72403 pos = [tooltipBox.left + tooltipBox.width + tooltipArrow, tipY];
72408 if (options.duration !== 0 || !tooltip.classed(side)) {
72409 tooltip.call(uiToggle(true));
72412 tooltip.style('top', pos[1] + 'px').style('left', pos[0] + 'px').attr('class', classes + ' ' + side); // shift popover-inner if it is very close to the top or bottom edge
72413 // (doesn't affect the placement of the popover-arrow)
72417 if (side === 'left' || side === 'right') {
72419 shiftY = 60 - pos[1];
72420 } else if (pos[1] + tip.height > h - 100) {
72421 shiftY = h - pos[1] - tip.height - 100;
72425 tooltip.selectAll('.popover-inner').style('top', shiftY + 'px');
72427 tooltip.classed('in', false).call(uiToggle(false));
72430 curtain.cut(box, options.duration);
72434 curtain.cut = function (datum, duration) {
72435 darkness.datum(datum).interrupt();
72438 if (duration === 0) {
72439 selection = darkness;
72441 selection = darkness.transition().duration(duration || 600).ease(linear$1);
72444 selection.attr('d', function (d) {
72445 var containerWidth = containerNode.clientWidth;
72446 var containerHeight = containerNode.clientHeight;
72447 var string = 'M 0,0 L 0,' + containerHeight + ' L ' + containerWidth + ',' + containerHeight + 'L' + containerWidth + ',0 Z';
72448 if (!d) return string;
72449 return string + 'M' + d.left + ',' + d.top + 'L' + d.left + ',' + (d.top + d.height) + 'L' + (d.left + d.width) + ',' + (d.top + d.height) + 'L' + (d.left + d.width) + ',' + d.top + 'Z';
72453 curtain.remove = function () {
72456 select(window).on('resize.curtain', null);
72457 }; // ClientRects are immutable, so copy them to an object,
72458 // in case we need to trim the height/width.
72461 function copyBox(src) {
72465 bottom: src.bottom,
72475 function uiIntroWelcome(context, reveal) {
72476 var dispatch = dispatch$8('done');
72478 title: 'intro.welcome.title'
72481 function welcome() {
72482 context.map().centerZoom([-85.63591, 41.94285], 19);
72483 reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.welcome'), {
72484 buttonText: _t.html('intro.ok'),
72485 buttonCallback: practice
72489 function practice() {
72490 reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.practice'), {
72491 buttonText: _t.html('intro.ok'),
72492 buttonCallback: words
72497 reveal('.intro-nav-wrap .chapter-welcome', helpHtml('intro.welcome.words'), {
72498 buttonText: _t.html('intro.ok'),
72499 buttonCallback: chapters
72503 function chapters() {
72504 dispatch.call('done');
72505 reveal('.intro-nav-wrap .chapter-navigation', helpHtml('intro.welcome.chapters', {
72506 next: _t('intro.navigation.title')
72510 chapter.enter = function () {
72514 chapter.exit = function () {
72515 context.container().select('.curtain-tooltip.intro-mouse').selectAll('.counter').remove();
72518 chapter.restart = function () {
72523 return utilRebind(chapter, dispatch, 'on');
72526 function uiIntroNavigation(context, reveal) {
72527 var dispatch = dispatch$8('done');
72529 var hallId = 'n2061';
72530 var townHall = [-85.63591, 41.94285];
72531 var springStreetId = 'w397';
72532 var springStreetEndId = 'n1834';
72533 var springStreet = [-85.63582, 41.94255];
72534 var onewayField = _mainPresetIndex.field('oneway');
72535 var maxspeedField = _mainPresetIndex.field('maxspeed');
72537 title: 'intro.navigation.title'
72540 function timeout(f, t) {
72541 timeouts.push(window.setTimeout(f, t));
72544 function eventCancel(d3_event) {
72545 d3_event.stopPropagation();
72546 d3_event.preventDefault();
72549 function isTownHallSelected() {
72550 var ids = context.selectedIDs();
72551 return ids.length === 1 && ids[0] === hallId;
72554 function dragMap() {
72555 context.enter(modeBrowse(context));
72556 context.history().reset('initial');
72557 var msec = transitionTime(townHall, context.map().center());
72560 reveal(null, null, {
72565 context.map().centerZoomEase(townHall, 19, msec);
72566 timeout(function () {
72567 var centerStart = context.map().center();
72568 var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
72569 var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
72570 reveal('.surface', dragString);
72571 context.map().on('drawn.intro', function () {
72572 reveal('.surface', dragString, {
72576 context.map().on('move.intro', function () {
72577 var centerNow = context.map().center();
72579 if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
72580 context.map().on('move.intro', null);
72581 timeout(function () {
72582 continueTo(zoomMap);
72588 function continueTo(nextStep) {
72589 context.map().on('move.intro drawn.intro', null);
72594 function zoomMap() {
72595 var zoomStart = context.map().zoom();
72596 var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
72597 var zoomString = helpHtml('intro.navigation.' + textId);
72598 reveal('.surface', zoomString);
72599 context.map().on('drawn.intro', function () {
72600 reveal('.surface', zoomString, {
72604 context.map().on('move.intro', function () {
72605 if (context.map().zoom() !== zoomStart) {
72606 context.map().on('move.intro', null);
72607 timeout(function () {
72608 continueTo(features);
72613 function continueTo(nextStep) {
72614 context.map().on('move.intro drawn.intro', null);
72619 function features() {
72620 var onClick = function onClick() {
72621 continueTo(pointsLinesAreas);
72624 reveal('.surface', helpHtml('intro.navigation.features'), {
72625 buttonText: _t.html('intro.ok'),
72626 buttonCallback: onClick
72628 context.map().on('drawn.intro', function () {
72629 reveal('.surface', helpHtml('intro.navigation.features'), {
72631 buttonText: _t.html('intro.ok'),
72632 buttonCallback: onClick
72636 function continueTo(nextStep) {
72637 context.map().on('drawn.intro', null);
72642 function pointsLinesAreas() {
72643 var onClick = function onClick() {
72644 continueTo(nodesWays);
72647 reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
72648 buttonText: _t.html('intro.ok'),
72649 buttonCallback: onClick
72651 context.map().on('drawn.intro', function () {
72652 reveal('.surface', helpHtml('intro.navigation.points_lines_areas'), {
72654 buttonText: _t.html('intro.ok'),
72655 buttonCallback: onClick
72659 function continueTo(nextStep) {
72660 context.map().on('drawn.intro', null);
72665 function nodesWays() {
72666 var onClick = function onClick() {
72667 continueTo(clickTownHall);
72670 reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
72671 buttonText: _t.html('intro.ok'),
72672 buttonCallback: onClick
72674 context.map().on('drawn.intro', function () {
72675 reveal('.surface', helpHtml('intro.navigation.nodes_ways'), {
72677 buttonText: _t.html('intro.ok'),
72678 buttonCallback: onClick
72682 function continueTo(nextStep) {
72683 context.map().on('drawn.intro', null);
72688 function clickTownHall() {
72689 context.enter(modeBrowse(context));
72690 context.history().reset('initial');
72691 var entity = context.hasEntity(hallId);
72692 if (!entity) return;
72693 reveal(null, null, {
72696 context.map().centerZoomEase(entity.loc, 19, 500);
72697 timeout(function () {
72698 var entity = context.hasEntity(hallId);
72699 if (!entity) return;
72700 var box = pointBox(entity.loc, context);
72701 var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
72702 reveal(box, helpHtml('intro.navigation.' + textId));
72703 context.map().on('move.intro drawn.intro', function () {
72704 var entity = context.hasEntity(hallId);
72705 if (!entity) return;
72706 var box = pointBox(entity.loc, context);
72707 reveal(box, helpHtml('intro.navigation.' + textId), {
72711 context.on('enter.intro', function () {
72712 if (isTownHallSelected()) continueTo(selectedTownHall);
72714 }, 550); // after centerZoomEase
72716 context.history().on('change.intro', function () {
72717 if (!context.hasEntity(hallId)) {
72718 continueTo(clickTownHall);
72722 function continueTo(nextStep) {
72723 context.on('enter.intro', null);
72724 context.map().on('move.intro drawn.intro', null);
72725 context.history().on('change.intro', null);
72730 function selectedTownHall() {
72731 if (!isTownHallSelected()) return clickTownHall();
72732 var entity = context.hasEntity(hallId);
72733 if (!entity) return clickTownHall();
72734 var box = pointBox(entity.loc, context);
72736 var onClick = function onClick() {
72737 continueTo(editorTownHall);
72740 reveal(box, helpHtml('intro.navigation.selected_townhall'), {
72741 buttonText: _t.html('intro.ok'),
72742 buttonCallback: onClick
72744 context.map().on('move.intro drawn.intro', function () {
72745 var entity = context.hasEntity(hallId);
72746 if (!entity) return;
72747 var box = pointBox(entity.loc, context);
72748 reveal(box, helpHtml('intro.navigation.selected_townhall'), {
72750 buttonText: _t.html('intro.ok'),
72751 buttonCallback: onClick
72754 context.history().on('change.intro', function () {
72755 if (!context.hasEntity(hallId)) {
72756 continueTo(clickTownHall);
72760 function continueTo(nextStep) {
72761 context.map().on('move.intro drawn.intro', null);
72762 context.history().on('change.intro', null);
72767 function editorTownHall() {
72768 if (!isTownHallSelected()) return clickTownHall(); // disallow scrolling
72770 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
72772 var onClick = function onClick() {
72773 continueTo(presetTownHall);
72776 reveal('.entity-editor-pane', helpHtml('intro.navigation.editor_townhall'), {
72777 buttonText: _t.html('intro.ok'),
72778 buttonCallback: onClick
72780 context.on('exit.intro', function () {
72781 continueTo(clickTownHall);
72783 context.history().on('change.intro', function () {
72784 if (!context.hasEntity(hallId)) {
72785 continueTo(clickTownHall);
72789 function continueTo(nextStep) {
72790 context.on('exit.intro', null);
72791 context.history().on('change.intro', null);
72792 context.container().select('.inspector-wrap').on('wheel.intro', null);
72797 function presetTownHall() {
72798 if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
72800 context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
72802 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel); // preset match, in case the user happened to change it.
72804 var entity = context.entity(context.selectedIDs()[0]);
72805 var preset = _mainPresetIndex.match(entity, context.graph());
72807 var onClick = function onClick() {
72808 continueTo(fieldsTownHall);
72811 reveal('.entity-editor-pane .section-feature-type', helpHtml('intro.navigation.preset_townhall', {
72812 preset: preset.name()
72814 buttonText: _t.html('intro.ok'),
72815 buttonCallback: onClick
72817 context.on('exit.intro', function () {
72818 continueTo(clickTownHall);
72820 context.history().on('change.intro', function () {
72821 if (!context.hasEntity(hallId)) {
72822 continueTo(clickTownHall);
72826 function continueTo(nextStep) {
72827 context.on('exit.intro', null);
72828 context.history().on('change.intro', null);
72829 context.container().select('.inspector-wrap').on('wheel.intro', null);
72834 function fieldsTownHall() {
72835 if (!isTownHallSelected()) return clickTownHall(); // reset pane, in case user happened to change it..
72837 context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // disallow scrolling
72839 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
72841 var onClick = function onClick() {
72842 continueTo(closeTownHall);
72845 reveal('.entity-editor-pane .section-preset-fields', helpHtml('intro.navigation.fields_townhall'), {
72846 buttonText: _t.html('intro.ok'),
72847 buttonCallback: onClick
72849 context.on('exit.intro', function () {
72850 continueTo(clickTownHall);
72852 context.history().on('change.intro', function () {
72853 if (!context.hasEntity(hallId)) {
72854 continueTo(clickTownHall);
72858 function continueTo(nextStep) {
72859 context.on('exit.intro', null);
72860 context.history().on('change.intro', null);
72861 context.container().select('.inspector-wrap').on('wheel.intro', null);
72866 function closeTownHall() {
72867 if (!isTownHallSelected()) return clickTownHall();
72868 var selector = '.entity-editor-pane button.close svg use';
72869 var href = select(selector).attr('href') || '#iD-icon-close';
72870 reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
72871 button: icon(href, 'inline')
72873 context.on('exit.intro', function () {
72874 continueTo(searchStreet);
72876 context.history().on('change.intro', function () {
72877 // update the close icon in the tooltip if the user edits something.
72878 var selector = '.entity-editor-pane button.close svg use';
72879 var href = select(selector).attr('href') || '#iD-icon-close';
72880 reveal('.entity-editor-pane', helpHtml('intro.navigation.close_townhall', {
72881 button: icon(href, 'inline')
72887 function continueTo(nextStep) {
72888 context.on('exit.intro', null);
72889 context.history().on('change.intro', null);
72894 function searchStreet() {
72895 context.enter(modeBrowse(context));
72896 context.history().reset('initial'); // ensure spring street exists
72898 var msec = transitionTime(springStreet, context.map().center());
72901 reveal(null, null, {
72906 context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
72908 timeout(function () {
72909 reveal('.search-header input', helpHtml('intro.navigation.search_street', {
72910 name: _t('intro.graph.name.spring-street')
72912 context.container().select('.search-header input').on('keyup.intro', checkSearchResult);
72916 function checkSearchResult() {
72917 var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
72919 var firstName = first.select('.entity-name');
72920 var name = _t('intro.graph.name.spring-street');
72922 if (!firstName.empty() && firstName.html() === name) {
72923 reveal(first.node(), helpHtml('intro.navigation.choose_street', {
72928 context.on('exit.intro', function () {
72929 continueTo(selectedStreet);
72931 context.container().select('.search-header input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
72934 function continueTo(nextStep) {
72935 context.on('exit.intro', null);
72936 context.container().select('.search-header input').on('keydown.intro', null).on('keyup.intro', null);
72941 function selectedStreet() {
72942 if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
72943 return searchStreet();
72946 var onClick = function onClick() {
72947 continueTo(editorStreet);
72950 var entity = context.entity(springStreetEndId);
72951 var box = pointBox(entity.loc, context);
72953 reveal(box, helpHtml('intro.navigation.selected_street', {
72954 name: _t('intro.graph.name.spring-street')
72957 buttonText: _t.html('intro.ok'),
72958 buttonCallback: onClick
72960 timeout(function () {
72961 context.map().on('move.intro drawn.intro', function () {
72962 var entity = context.hasEntity(springStreetEndId);
72963 if (!entity) return;
72964 var box = pointBox(entity.loc, context);
72966 reveal(box, helpHtml('intro.navigation.selected_street', {
72967 name: _t('intro.graph.name.spring-street')
72970 buttonText: _t.html('intro.ok'),
72971 buttonCallback: onClick
72974 }, 600); // after reveal.
72976 context.on('enter.intro', function (mode) {
72977 if (!context.hasEntity(springStreetId)) {
72978 return continueTo(searchStreet);
72981 var ids = context.selectedIDs();
72983 if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
72984 // keep Spring Street selected..
72985 context.enter(modeSelect(context, [springStreetId]));
72988 context.history().on('change.intro', function () {
72989 if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
72990 timeout(function () {
72991 continueTo(searchStreet);
72992 }, 300); // after any transition (e.g. if user deleted intersection)
72996 function continueTo(nextStep) {
72997 context.map().on('move.intro drawn.intro', null);
72998 context.on('enter.intro', null);
72999 context.history().on('change.intro', null);
73004 function editorStreet() {
73005 var selector = '.entity-editor-pane button.close svg use';
73006 var href = select(selector).attr('href') || '#iD-icon-close';
73007 reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
73008 button: icon(href, 'inline'),
73009 field1: onewayField.label(),
73010 field2: maxspeedField.label()
73012 context.on('exit.intro', function () {
73015 context.history().on('change.intro', function () {
73016 // update the close icon in the tooltip if the user edits something.
73017 var selector = '.entity-editor-pane button.close svg use';
73018 var href = select(selector).attr('href') || '#iD-icon-close';
73019 reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' + helpHtml('intro.navigation.editor_street', {
73020 button: icon(href, 'inline'),
73021 field1: onewayField.label(),
73022 field2: maxspeedField.label()
73028 function continueTo(nextStep) {
73029 context.on('exit.intro', null);
73030 context.history().on('change.intro', null);
73036 dispatch.call('done');
73037 reveal('.ideditor', helpHtml('intro.navigation.play', {
73038 next: _t('intro.points.title')
73040 tooltipBox: '.intro-nav-wrap .chapter-point',
73041 buttonText: _t.html('intro.ok'),
73042 buttonCallback: function buttonCallback() {
73043 reveal('.ideditor');
73048 chapter.enter = function () {
73052 chapter.exit = function () {
73053 timeouts.forEach(window.clearTimeout);
73054 context.on('enter.intro exit.intro', null);
73055 context.map().on('move.intro drawn.intro', null);
73056 context.history().on('change.intro', null);
73057 context.container().select('.inspector-wrap').on('wheel.intro', null);
73058 context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
73061 chapter.restart = function () {
73066 return utilRebind(chapter, dispatch, 'on');
73069 function uiIntroPoint(context, reveal) {
73070 var dispatch = dispatch$8('done');
73072 var intersection = [-85.63279, 41.94394];
73073 var building = [-85.632422, 41.944045];
73074 var cafePreset = _mainPresetIndex.item('amenity/cafe');
73075 var _pointID = null;
73077 title: 'intro.points.title'
73080 function timeout(f, t) {
73081 timeouts.push(window.setTimeout(f, t));
73084 function eventCancel(d3_event) {
73085 d3_event.stopPropagation();
73086 d3_event.preventDefault();
73089 function addPoint() {
73090 context.enter(modeBrowse(context));
73091 context.history().reset('initial');
73092 var msec = transitionTime(intersection, context.map().center());
73095 reveal(null, null, {
73100 context.map().centerZoomEase(intersection, 19, msec);
73101 timeout(function () {
73102 var tooltip = reveal('button.add-point', helpHtml('intro.points.points_info') + '{br}' + helpHtml('intro.points.add_point'));
73104 tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-points');
73105 context.on('enter.intro', function (mode) {
73106 if (mode.id !== 'add-point') return;
73107 continueTo(placePoint);
73111 function continueTo(nextStep) {
73112 context.on('enter.intro', null);
73117 function placePoint() {
73118 if (context.mode().id !== 'add-point') {
73119 return chapter.restart();
73122 var pointBox = pad(building, 150, context);
73123 var textId = context.lastPointerType() === 'mouse' ? 'place_point' : 'place_point_touch';
73124 reveal(pointBox, helpHtml('intro.points.' + textId));
73125 context.map().on('move.intro drawn.intro', function () {
73126 pointBox = pad(building, 150, context);
73127 reveal(pointBox, helpHtml('intro.points.' + textId), {
73131 context.on('enter.intro', function (mode) {
73132 if (mode.id !== 'select') return chapter.restart();
73133 _pointID = context.mode().selectedIDs()[0];
73134 continueTo(searchPreset);
73137 function continueTo(nextStep) {
73138 context.map().on('move.intro drawn.intro', null);
73139 context.on('enter.intro', null);
73144 function searchPreset() {
73145 if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73147 } // disallow scrolling
73150 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73151 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73152 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
73153 preset: cafePreset.name()
73155 context.on('enter.intro', function (mode) {
73156 if (!_pointID || !context.hasEntity(_pointID)) {
73157 return continueTo(addPoint);
73160 var ids = context.selectedIDs();
73162 if (mode.id !== 'select' || !ids.length || ids[0] !== _pointID) {
73163 // keep the user's point selected..
73164 context.enter(modeSelect(context, [_pointID])); // disallow scrolling
73166 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73167 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73168 reveal('.preset-search-input', helpHtml('intro.points.search_cafe', {
73169 preset: cafePreset.name()
73171 context.history().on('change.intro', null);
73175 function checkPresetSearch() {
73176 var first = context.container().select('.preset-list-item:first-child');
73178 if (first.classed('preset-amenity-cafe')) {
73179 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
73180 reveal(first.select('.preset-list-button').node(), helpHtml('intro.points.choose_cafe', {
73181 preset: cafePreset.name()
73185 context.history().on('change.intro', function () {
73186 continueTo(aboutFeatureEditor);
73191 function continueTo(nextStep) {
73192 context.on('enter.intro', null);
73193 context.history().on('change.intro', null);
73194 context.container().select('.inspector-wrap').on('wheel.intro', null);
73195 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73200 function aboutFeatureEditor() {
73201 if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73205 timeout(function () {
73206 reveal('.entity-editor-pane', helpHtml('intro.points.feature_editor'), {
73207 tooltipClass: 'intro-points-describe',
73208 buttonText: _t.html('intro.ok'),
73209 buttonCallback: function buttonCallback() {
73210 continueTo(addName);
73214 context.on('exit.intro', function () {
73215 // if user leaves select mode here, just continue with the tutorial.
73216 continueTo(reselectPoint);
73219 function continueTo(nextStep) {
73220 context.on('exit.intro', null);
73225 function addName() {
73226 if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73228 } // reset pane, in case user happened to change it..
73231 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73232 var addNameString = helpHtml('intro.points.fields_info') + '{br}' + helpHtml('intro.points.add_name');
73233 timeout(function () {
73234 // It's possible for the user to add a name in a previous step..
73235 // If so, don't tell them to add the name in this step.
73236 // Give them an OK button instead.
73237 var entity = context.entity(_pointID);
73239 if (entity.tags.name) {
73240 var tooltip = reveal('.entity-editor-pane', addNameString, {
73241 tooltipClass: 'intro-points-describe',
73242 buttonText: _t.html('intro.ok'),
73243 buttonCallback: function buttonCallback() {
73244 continueTo(addCloseEditor);
73247 tooltip.select('.instruction').style('display', 'none');
73249 reveal('.entity-editor-pane', addNameString, {
73250 tooltipClass: 'intro-points-describe'
73254 context.history().on('change.intro', function () {
73255 continueTo(addCloseEditor);
73257 context.on('exit.intro', function () {
73258 // if user leaves select mode here, just continue with the tutorial.
73259 continueTo(reselectPoint);
73262 function continueTo(nextStep) {
73263 context.on('exit.intro', null);
73264 context.history().on('change.intro', null);
73269 function addCloseEditor() {
73270 // reset pane, in case user happened to change it..
73271 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73272 var selector = '.entity-editor-pane button.close svg use';
73273 var href = select(selector).attr('href') || '#iD-icon-close';
73274 context.on('exit.intro', function () {
73275 continueTo(reselectPoint);
73277 reveal('.entity-editor-pane', helpHtml('intro.points.add_close', {
73278 button: icon(href, 'inline')
73281 function continueTo(nextStep) {
73282 context.on('exit.intro', null);
73287 function reselectPoint() {
73288 if (!_pointID) return chapter.restart();
73289 var entity = context.hasEntity(_pointID);
73290 if (!entity) return chapter.restart(); // make sure it's still a cafe, in case user somehow changed it..
73292 var oldPreset = _mainPresetIndex.match(entity, context.graph());
73293 context.replace(actionChangePreset(_pointID, oldPreset, cafePreset));
73294 context.enter(modeBrowse(context));
73295 var msec = transitionTime(entity.loc, context.map().center());
73298 reveal(null, null, {
73303 context.map().centerEase(entity.loc, msec);
73304 timeout(function () {
73305 var box = pointBox(entity.loc, context);
73306 reveal(box, helpHtml('intro.points.reselect'), {
73309 timeout(function () {
73310 context.map().on('move.intro drawn.intro', function () {
73311 var entity = context.hasEntity(_pointID);
73312 if (!entity) return chapter.restart();
73313 var box = pointBox(entity.loc, context);
73314 reveal(box, helpHtml('intro.points.reselect'), {
73318 }, 600); // after reveal..
73320 context.on('enter.intro', function (mode) {
73321 if (mode.id !== 'select') return;
73322 continueTo(updatePoint);
73326 function continueTo(nextStep) {
73327 context.map().on('move.intro drawn.intro', null);
73328 context.on('enter.intro', null);
73333 function updatePoint() {
73334 if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73335 return continueTo(reselectPoint);
73336 } // reset pane, in case user happened to untag the point..
73339 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73340 context.on('exit.intro', function () {
73341 continueTo(reselectPoint);
73343 context.history().on('change.intro', function () {
73344 continueTo(updateCloseEditor);
73346 timeout(function () {
73347 reveal('.entity-editor-pane', helpHtml('intro.points.update'), {
73348 tooltipClass: 'intro-points-describe'
73352 function continueTo(nextStep) {
73353 context.on('exit.intro', null);
73354 context.history().on('change.intro', null);
73359 function updateCloseEditor() {
73360 if (context.mode().id !== 'select' || !_pointID || !context.hasEntity(_pointID)) {
73361 return continueTo(reselectPoint);
73362 } // reset pane, in case user happened to change it..
73365 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73366 context.on('exit.intro', function () {
73367 continueTo(rightClickPoint);
73369 timeout(function () {
73370 reveal('.entity-editor-pane', helpHtml('intro.points.update_close', {
73371 button: icon('#iD-icon-close', 'inline')
73375 function continueTo(nextStep) {
73376 context.on('exit.intro', null);
73381 function rightClickPoint() {
73382 if (!_pointID) return chapter.restart();
73383 var entity = context.hasEntity(_pointID);
73384 if (!entity) return chapter.restart();
73385 context.enter(modeBrowse(context));
73386 var box = pointBox(entity.loc, context);
73387 var textId = context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch';
73388 reveal(box, helpHtml('intro.points.' + textId), {
73391 timeout(function () {
73392 context.map().on('move.intro', function () {
73393 var entity = context.hasEntity(_pointID);
73394 if (!entity) return chapter.restart();
73395 var box = pointBox(entity.loc, context);
73396 reveal(box, helpHtml('intro.points.' + textId), {
73400 }, 600); // after reveal
73402 context.on('enter.intro', function (mode) {
73403 if (mode.id !== 'select') return;
73404 var ids = context.selectedIDs();
73405 if (ids.length !== 1 || ids[0] !== _pointID) return;
73406 timeout(function () {
73407 var node = selectMenuItem(context, 'delete').node();
73409 continueTo(enterDelete);
73410 }, 50); // after menu visible
73413 function continueTo(nextStep) {
73414 context.on('enter.intro', null);
73415 context.map().on('move.intro', null);
73420 function enterDelete() {
73421 if (!_pointID) return chapter.restart();
73422 var entity = context.hasEntity(_pointID);
73423 if (!entity) return chapter.restart();
73424 var node = selectMenuItem(context, 'delete').node();
73427 return continueTo(rightClickPoint);
73430 reveal('.edit-menu', helpHtml('intro.points.delete'), {
73433 timeout(function () {
73434 context.map().on('move.intro', function () {
73435 reveal('.edit-menu', helpHtml('intro.points.delete'), {
73440 }, 300); // after menu visible
73442 context.on('exit.intro', function () {
73443 if (!_pointID) return chapter.restart();
73444 var entity = context.hasEntity(_pointID);
73445 if (entity) return continueTo(rightClickPoint); // point still exists
73447 context.history().on('change.intro', function (changed) {
73448 if (changed.deleted().length) {
73453 function continueTo(nextStep) {
73454 context.map().on('move.intro', null);
73455 context.history().on('change.intro', null);
73456 context.on('exit.intro', null);
73462 context.history().on('change.intro', function () {
73465 reveal('.top-toolbar button.undo-button', helpHtml('intro.points.undo'));
73467 function continueTo(nextStep) {
73468 context.history().on('change.intro', null);
73474 dispatch.call('done');
73475 reveal('.ideditor', helpHtml('intro.points.play', {
73476 next: _t('intro.areas.title')
73478 tooltipBox: '.intro-nav-wrap .chapter-area',
73479 buttonText: _t.html('intro.ok'),
73480 buttonCallback: function buttonCallback() {
73481 reveal('.ideditor');
73486 chapter.enter = function () {
73490 chapter.exit = function () {
73491 timeouts.forEach(window.clearTimeout);
73492 context.on('enter.intro exit.intro', null);
73493 context.map().on('move.intro drawn.intro', null);
73494 context.history().on('change.intro', null);
73495 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73496 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73499 chapter.restart = function () {
73504 return utilRebind(chapter, dispatch, 'on');
73507 function uiIntroArea(context, reveal) {
73508 var dispatch = dispatch$8('done');
73509 var playground = [-85.63552, 41.94159];
73510 var playgroundPreset = _mainPresetIndex.item('leisure/playground');
73511 var nameField = _mainPresetIndex.field('name');
73512 var descriptionField = _mainPresetIndex.field('description');
73518 title: 'intro.areas.title'
73521 function timeout(f, t) {
73522 timeouts.push(window.setTimeout(f, t));
73525 function eventCancel(d3_event) {
73526 d3_event.stopPropagation();
73527 d3_event.preventDefault();
73530 function revealPlayground(center, text, options) {
73531 var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
73532 var box = pad(center, padding, context);
73533 reveal(box, text, options);
73536 function addArea() {
73537 context.enter(modeBrowse(context));
73538 context.history().reset('initial');
73540 var msec = transitionTime(playground, context.map().center());
73543 reveal(null, null, {
73548 context.map().centerZoomEase(playground, 19, msec);
73549 timeout(function () {
73550 var tooltip = reveal('button.add-area', helpHtml('intro.areas.add_playground'));
73551 tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-areas');
73552 context.on('enter.intro', function (mode) {
73553 if (mode.id !== 'add-area') return;
73554 continueTo(startPlayground);
73558 function continueTo(nextStep) {
73559 context.on('enter.intro', null);
73564 function startPlayground() {
73565 if (context.mode().id !== 'add-area') {
73566 return chapter.restart();
73570 context.map().zoomEase(19.5, 500);
73571 timeout(function () {
73572 var textId = context.lastPointerType() === 'mouse' ? 'starting_node_click' : 'starting_node_tap';
73573 var startDrawString = helpHtml('intro.areas.start_playground') + helpHtml('intro.areas.' + textId);
73574 revealPlayground(playground, startDrawString, {
73577 timeout(function () {
73578 context.map().on('move.intro drawn.intro', function () {
73579 revealPlayground(playground, startDrawString, {
73583 context.on('enter.intro', function (mode) {
73584 if (mode.id !== 'draw-area') return chapter.restart();
73585 continueTo(continuePlayground);
73587 }, 250); // after reveal
73588 }, 550); // after easing
73590 function continueTo(nextStep) {
73591 context.map().on('move.intro drawn.intro', null);
73592 context.on('enter.intro', null);
73597 function continuePlayground() {
73598 if (context.mode().id !== 'draw-area') {
73599 return chapter.restart();
73603 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
73606 timeout(function () {
73607 context.map().on('move.intro drawn.intro', function () {
73608 revealPlayground(playground, helpHtml('intro.areas.continue_playground'), {
73612 }, 250); // after reveal
73614 context.on('enter.intro', function (mode) {
73615 if (mode.id === 'draw-area') {
73616 var entity = context.hasEntity(context.selectedIDs()[0]);
73618 if (entity && entity.nodes.length >= 6) {
73619 return continueTo(finishPlayground);
73623 } else if (mode.id === 'select') {
73624 _areaID = context.selectedIDs()[0];
73625 return continueTo(searchPresets);
73627 return chapter.restart();
73631 function continueTo(nextStep) {
73632 context.map().on('move.intro drawn.intro', null);
73633 context.on('enter.intro', null);
73638 function finishPlayground() {
73639 if (context.mode().id !== 'draw-area') {
73640 return chapter.restart();
73644 var finishString = helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.areas.finish_playground');
73645 revealPlayground(playground, finishString, {
73648 timeout(function () {
73649 context.map().on('move.intro drawn.intro', function () {
73650 revealPlayground(playground, finishString, {
73654 }, 250); // after reveal
73656 context.on('enter.intro', function (mode) {
73657 if (mode.id === 'draw-area') {
73659 } else if (mode.id === 'select') {
73660 _areaID = context.selectedIDs()[0];
73661 return continueTo(searchPresets);
73663 return chapter.restart();
73667 function continueTo(nextStep) {
73668 context.map().on('move.intro drawn.intro', null);
73669 context.on('enter.intro', null);
73674 function searchPresets() {
73675 if (!_areaID || !context.hasEntity(_areaID)) {
73679 var ids = context.selectedIDs();
73681 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73682 context.enter(modeSelect(context, [_areaID]));
73683 } // disallow scrolling
73686 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73687 timeout(function () {
73688 // reset pane, in case user somehow happened to change it..
73689 context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
73690 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73691 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
73692 preset: playgroundPreset.name()
73694 }, 400); // after preset list pane visible..
73696 context.on('enter.intro', function (mode) {
73697 if (!_areaID || !context.hasEntity(_areaID)) {
73698 return continueTo(addArea);
73701 var ids = context.selectedIDs();
73703 if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
73704 // keep the user's area selected..
73705 context.enter(modeSelect(context, [_areaID])); // reset pane, in case user somehow happened to change it..
73707 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
73709 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73710 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
73711 reveal('.preset-search-input', helpHtml('intro.areas.search_playground', {
73712 preset: playgroundPreset.name()
73714 context.history().on('change.intro', null);
73718 function checkPresetSearch() {
73719 var first = context.container().select('.preset-list-item:first-child');
73721 if (first.classed('preset-leisure-playground')) {
73722 reveal(first.select('.preset-list-button').node(), helpHtml('intro.areas.choose_playground', {
73723 preset: playgroundPreset.name()
73727 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
73728 context.history().on('change.intro', function () {
73729 continueTo(clickAddField);
73734 function continueTo(nextStep) {
73735 context.container().select('.inspector-wrap').on('wheel.intro', null);
73736 context.on('enter.intro', null);
73737 context.history().on('change.intro', null);
73738 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73743 function clickAddField() {
73744 if (!_areaID || !context.hasEntity(_areaID)) {
73748 var ids = context.selectedIDs();
73750 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73751 return searchPresets();
73754 if (!context.container().select('.form-field-description').empty()) {
73755 return continueTo(describePlayground);
73756 } // disallow scrolling
73759 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
73760 timeout(function () {
73761 // reset pane, in case user somehow happened to change it..
73762 context.container().select('.inspector-wrap .panewrap').style('right', '0%'); // It's possible for the user to add a description in a previous step..
73763 // If they did this already, just continue to next step.
73765 var entity = context.entity(_areaID);
73767 if (entity.tags.description) {
73768 return continueTo(play);
73769 } // scroll "Add field" into view
73772 var box = context.container().select('.more-fields').node().getBoundingClientRect();
73774 if (box.top > 300) {
73775 var pane = context.container().select('.entity-editor-pane .inspector-body');
73776 var start = pane.node().scrollTop;
73777 var end = start + (box.top - 300);
73778 pane.transition().duration(250).tween('scroll.inspector', function () {
73780 var i = d3_interpolateNumber(start, end);
73781 return function (t) {
73782 node.scrollTop = i(t);
73787 timeout(function () {
73788 reveal('.more-fields .combobox-input', helpHtml('intro.areas.add_field', {
73789 name: nameField.label(),
73790 description: descriptionField.label()
73794 context.container().select('.more-fields .combobox-input').on('click.intro', function () {
73795 // Watch for the combobox to appear...
73797 watcher = window.setInterval(function () {
73798 if (!context.container().select('div.combobox').empty()) {
73799 window.clearInterval(watcher);
73800 continueTo(chooseDescriptionField);
73804 }, 300); // after "Add Field" visible
73805 }, 400); // after editor pane visible
73807 context.on('exit.intro', function () {
73808 return continueTo(searchPresets);
73811 function continueTo(nextStep) {
73812 context.container().select('.inspector-wrap').on('wheel.intro', null);
73813 context.container().select('.more-fields .combobox-input').on('click.intro', null);
73814 context.on('exit.intro', null);
73819 function chooseDescriptionField() {
73820 if (!_areaID || !context.hasEntity(_areaID)) {
73824 var ids = context.selectedIDs();
73826 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73827 return searchPresets();
73830 if (!context.container().select('.form-field-description').empty()) {
73831 return continueTo(describePlayground);
73832 } // Make sure combobox is ready..
73835 if (context.container().select('div.combobox').empty()) {
73836 return continueTo(clickAddField);
73837 } // Watch for the combobox to go away..
73841 watcher = window.setInterval(function () {
73842 if (context.container().select('div.combobox').empty()) {
73843 window.clearInterval(watcher);
73844 timeout(function () {
73845 if (context.container().select('.form-field-description').empty()) {
73846 continueTo(retryChooseDescription);
73848 continueTo(describePlayground);
73850 }, 300); // after description field added.
73853 reveal('div.combobox', helpHtml('intro.areas.choose_field', {
73854 field: descriptionField.label()
73858 context.on('exit.intro', function () {
73859 return continueTo(searchPresets);
73862 function continueTo(nextStep) {
73863 if (watcher) window.clearInterval(watcher);
73864 context.on('exit.intro', null);
73869 function describePlayground() {
73870 if (!_areaID || !context.hasEntity(_areaID)) {
73874 var ids = context.selectedIDs();
73876 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73877 return searchPresets();
73878 } // reset pane, in case user happened to change it..
73881 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73883 if (context.container().select('.form-field-description').empty()) {
73884 return continueTo(retryChooseDescription);
73887 context.on('exit.intro', function () {
73890 reveal('.entity-editor-pane', helpHtml('intro.areas.describe_playground', {
73891 button: icon('#iD-icon-close', 'inline')
73896 function continueTo(nextStep) {
73897 context.on('exit.intro', null);
73902 function retryChooseDescription() {
73903 if (!_areaID || !context.hasEntity(_areaID)) {
73907 var ids = context.selectedIDs();
73909 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
73910 return searchPresets();
73911 } // reset pane, in case user happened to change it..
73914 context.container().select('.inspector-wrap .panewrap').style('right', '0%');
73915 reveal('.entity-editor-pane', helpHtml('intro.areas.retry_add_field', {
73916 field: descriptionField.label()
73918 buttonText: _t.html('intro.ok'),
73919 buttonCallback: function buttonCallback() {
73920 continueTo(clickAddField);
73923 context.on('exit.intro', function () {
73924 return continueTo(searchPresets);
73927 function continueTo(nextStep) {
73928 context.on('exit.intro', null);
73934 dispatch.call('done');
73935 reveal('.ideditor', helpHtml('intro.areas.play', {
73936 next: _t('intro.lines.title')
73938 tooltipBox: '.intro-nav-wrap .chapter-line',
73939 buttonText: _t.html('intro.ok'),
73940 buttonCallback: function buttonCallback() {
73941 reveal('.ideditor');
73946 chapter.enter = function () {
73950 chapter.exit = function () {
73951 timeouts.forEach(window.clearTimeout);
73952 context.on('enter.intro exit.intro', null);
73953 context.map().on('move.intro drawn.intro', null);
73954 context.history().on('change.intro', null);
73955 context.container().select('.inspector-wrap').on('wheel.intro', null);
73956 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
73957 context.container().select('.more-fields .combobox-input').on('click.intro', null);
73960 chapter.restart = function () {
73965 return utilRebind(chapter, dispatch, 'on');
73968 function uiIntroLine(context, reveal) {
73969 var dispatch = dispatch$8('done');
73971 var _tulipRoadID = null;
73972 var flowerRoadID = 'w646';
73973 var tulipRoadStart = [-85.6297754121684, 41.95805253325314];
73974 var tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204];
73975 var tulipRoadIntersection = [-85.62974496187628, 41.95742515554585];
73976 var roadCategory = _mainPresetIndex.item('category-road_minor');
73977 var residentialPreset = _mainPresetIndex.item('highway/residential');
73978 var woodRoadID = 'w525';
73979 var woodRoadEndID = 'n2862';
73980 var woodRoadAddNode = [-85.62390110349587, 41.95397111462291];
73981 var woodRoadDragEndpoint = [-85.623867390213, 41.95466987786487];
73982 var woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872];
73983 var washingtonStreetID = 'w522';
73984 var twelfthAvenueID = 'w1';
73985 var eleventhAvenueEndID = 'n3550';
73986 var twelfthAvenueEndID = 'n5';
73987 var _washingtonSegmentID = null;
73988 var eleventhAvenueEnd = context.entity(eleventhAvenueEndID).loc;
73989 var twelfthAvenueEnd = context.entity(twelfthAvenueEndID).loc;
73990 var deleteLinesLoc = [-85.6219395542764, 41.95228033922477];
73991 var twelfthAvenue = [-85.62219310052491, 41.952505413152956];
73993 title: 'intro.lines.title'
73996 function timeout(f, t) {
73997 timeouts.push(window.setTimeout(f, t));
74000 function eventCancel(d3_event) {
74001 d3_event.stopPropagation();
74002 d3_event.preventDefault();
74005 function addLine() {
74006 context.enter(modeBrowse(context));
74007 context.history().reset('initial');
74008 var msec = transitionTime(tulipRoadStart, context.map().center());
74011 reveal(null, null, {
74016 context.map().centerZoomEase(tulipRoadStart, 18.5, msec);
74017 timeout(function () {
74018 var tooltip = reveal('button.add-line', helpHtml('intro.lines.add_line'));
74019 tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-lines');
74020 context.on('enter.intro', function (mode) {
74021 if (mode.id !== 'add-line') return;
74022 continueTo(startLine);
74026 function continueTo(nextStep) {
74027 context.on('enter.intro', null);
74032 function startLine() {
74033 if (context.mode().id !== 'add-line') return chapter.restart();
74034 _tulipRoadID = null;
74035 var padding = 70 * Math.pow(2, context.map().zoom() - 18);
74036 var box = pad(tulipRoadStart, padding, context);
74037 box.height = box.height + 100;
74038 var textId = context.lastPointerType() === 'mouse' ? 'start_line' : 'start_line_tap';
74039 var startLineString = helpHtml('intro.lines.missing_road') + '{br}' + helpHtml('intro.lines.line_draw_info') + helpHtml('intro.lines.' + textId);
74040 reveal(box, startLineString);
74041 context.map().on('move.intro drawn.intro', function () {
74042 padding = 70 * Math.pow(2, context.map().zoom() - 18);
74043 box = pad(tulipRoadStart, padding, context);
74044 box.height = box.height + 100;
74045 reveal(box, startLineString, {
74049 context.on('enter.intro', function (mode) {
74050 if (mode.id !== 'draw-line') return chapter.restart();
74051 continueTo(drawLine);
74054 function continueTo(nextStep) {
74055 context.map().on('move.intro drawn.intro', null);
74056 context.on('enter.intro', null);
74061 function drawLine() {
74062 if (context.mode().id !== 'draw-line') return chapter.restart();
74063 _tulipRoadID = context.mode().selectedIDs()[0];
74064 context.map().centerEase(tulipRoadMidpoint, 500);
74065 timeout(function () {
74066 var padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
74067 var box = pad(tulipRoadMidpoint, padding, context);
74068 box.height = box.height * 2;
74069 reveal(box, helpHtml('intro.lines.intersect', {
74070 name: _t('intro.graph.name.flower-street')
74072 context.map().on('move.intro drawn.intro', function () {
74073 padding = 200 * Math.pow(2, context.map().zoom() - 18.5);
74074 box = pad(tulipRoadMidpoint, padding, context);
74075 box.height = box.height * 2;
74076 reveal(box, helpHtml('intro.lines.intersect', {
74077 name: _t('intro.graph.name.flower-street')
74082 }, 550); // after easing..
74084 context.history().on('change.intro', function () {
74085 if (isLineConnected()) {
74086 continueTo(continueLine);
74089 context.on('enter.intro', function (mode) {
74090 if (mode.id === 'draw-line') {
74092 } else if (mode.id === 'select') {
74093 continueTo(retryIntersect);
74096 return chapter.restart();
74100 function continueTo(nextStep) {
74101 context.map().on('move.intro drawn.intro', null);
74102 context.history().on('change.intro', null);
74103 context.on('enter.intro', null);
74108 function isLineConnected() {
74109 var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
74111 if (!entity) return false;
74112 var drawNodes = context.graph().childNodes(entity);
74113 return drawNodes.some(function (node) {
74114 return context.graph().parentWays(node).some(function (parent) {
74115 return parent.id === flowerRoadID;
74120 function retryIntersect() {
74121 select(window).on('pointerdown.intro mousedown.intro', eventCancel, true);
74122 var box = pad(tulipRoadIntersection, 80, context);
74123 reveal(box, helpHtml('intro.lines.retry_intersect', {
74124 name: _t('intro.graph.name.flower-street')
74126 timeout(chapter.restart, 3000);
74129 function continueLine() {
74130 if (context.mode().id !== 'draw-line') return chapter.restart();
74132 var entity = _tulipRoadID && context.hasEntity(_tulipRoadID);
74134 if (!entity) return chapter.restart();
74135 context.map().centerEase(tulipRoadIntersection, 500);
74136 var continueLineText = helpHtml('intro.lines.continue_line') + '{br}' + helpHtml('intro.lines.finish_line_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.lines.finish_road');
74137 reveal('.surface', continueLineText);
74138 context.on('enter.intro', function (mode) {
74139 if (mode.id === 'draw-line') {
74141 } else if (mode.id === 'select') {
74142 return continueTo(chooseCategoryRoad);
74144 return chapter.restart();
74148 function continueTo(nextStep) {
74149 context.on('enter.intro', null);
74154 function chooseCategoryRoad() {
74155 if (context.mode().id !== 'select') return chapter.restart();
74156 context.on('exit.intro', function () {
74157 return chapter.restart();
74159 var button = context.container().select('.preset-category-road_minor .preset-list-button');
74160 if (button.empty()) return chapter.restart(); // disallow scrolling
74162 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74163 timeout(function () {
74164 // reset pane, in case user somehow happened to change it..
74165 context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
74166 reveal(button.node(), helpHtml('intro.lines.choose_category_road', {
74167 category: roadCategory.name()
74169 button.on('click.intro', function () {
74170 continueTo(choosePresetResidential);
74172 }, 400); // after editor pane visible
74174 function continueTo(nextStep) {
74175 context.container().select('.inspector-wrap').on('wheel.intro', null);
74176 context.container().select('.preset-list-button').on('click.intro', null);
74177 context.on('exit.intro', null);
74182 function choosePresetResidential() {
74183 if (context.mode().id !== 'select') return chapter.restart();
74184 context.on('exit.intro', function () {
74185 return chapter.restart();
74187 var subgrid = context.container().select('.preset-category-road_minor .subgrid');
74188 if (subgrid.empty()) return chapter.restart();
74189 subgrid.selectAll(':not(.preset-highway-residential) .preset-list-button').on('click.intro', function () {
74190 continueTo(retryPresetResidential);
74192 subgrid.selectAll('.preset-highway-residential .preset-list-button').on('click.intro', function () {
74193 continueTo(nameRoad);
74195 timeout(function () {
74196 reveal(subgrid.node(), helpHtml('intro.lines.choose_preset_residential', {
74197 preset: residentialPreset.name()
74199 tooltipBox: '.preset-highway-residential .preset-list-button',
74204 function continueTo(nextStep) {
74205 context.container().select('.preset-list-button').on('click.intro', null);
74206 context.on('exit.intro', null);
74209 } // selected wrong road type
74212 function retryPresetResidential() {
74213 if (context.mode().id !== 'select') return chapter.restart();
74214 context.on('exit.intro', function () {
74215 return chapter.restart();
74216 }); // disallow scrolling
74218 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
74219 timeout(function () {
74220 var button = context.container().select('.entity-editor-pane .preset-list-button');
74221 reveal(button.node(), helpHtml('intro.lines.retry_preset_residential', {
74222 preset: residentialPreset.name()
74224 button.on('click.intro', function () {
74225 continueTo(chooseCategoryRoad);
74229 function continueTo(nextStep) {
74230 context.container().select('.inspector-wrap').on('wheel.intro', null);
74231 context.container().select('.preset-list-button').on('click.intro', null);
74232 context.on('exit.intro', null);
74237 function nameRoad() {
74238 context.on('exit.intro', function () {
74239 continueTo(didNameRoad);
74241 timeout(function () {
74242 reveal('.entity-editor-pane', helpHtml('intro.lines.name_road', {
74243 button: icon('#iD-icon-close', 'inline')
74245 tooltipClass: 'intro-lines-name_road'
74249 function continueTo(nextStep) {
74250 context.on('exit.intro', null);
74255 function didNameRoad() {
74256 context.history().checkpoint('doneAddLine');
74257 timeout(function () {
74258 reveal('.surface', helpHtml('intro.lines.did_name_road'), {
74259 buttonText: _t.html('intro.ok'),
74260 buttonCallback: function buttonCallback() {
74261 continueTo(updateLine);
74266 function continueTo(nextStep) {
74271 function updateLine() {
74272 context.history().reset('doneAddLine');
74274 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74275 return chapter.restart();
74278 var msec = transitionTime(woodRoadDragMidpoint, context.map().center());
74281 reveal(null, null, {
74286 context.map().centerZoomEase(woodRoadDragMidpoint, 19, msec);
74287 timeout(function () {
74288 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
74289 var box = pad(woodRoadDragMidpoint, padding, context);
74291 var advance = function advance() {
74292 continueTo(addNode);
74295 reveal(box, helpHtml('intro.lines.update_line'), {
74296 buttonText: _t.html('intro.ok'),
74297 buttonCallback: advance
74299 context.map().on('move.intro drawn.intro', function () {
74300 var padding = 250 * Math.pow(2, context.map().zoom() - 19);
74301 var box = pad(woodRoadDragMidpoint, padding, context);
74302 reveal(box, helpHtml('intro.lines.update_line'), {
74304 buttonText: _t.html('intro.ok'),
74305 buttonCallback: advance
74310 function continueTo(nextStep) {
74311 context.map().on('move.intro drawn.intro', null);
74316 function addNode() {
74317 context.history().reset('doneAddLine');
74319 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74320 return chapter.restart();
74323 var padding = 40 * Math.pow(2, context.map().zoom() - 19);
74324 var box = pad(woodRoadAddNode, padding, context);
74325 var addNodeString = helpHtml('intro.lines.add_node' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
74326 reveal(box, addNodeString);
74327 context.map().on('move.intro drawn.intro', function () {
74328 var padding = 40 * Math.pow(2, context.map().zoom() - 19);
74329 var box = pad(woodRoadAddNode, padding, context);
74330 reveal(box, addNodeString, {
74334 context.history().on('change.intro', function (changed) {
74335 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74336 return continueTo(updateLine);
74339 if (changed.created().length === 1) {
74340 timeout(function () {
74341 continueTo(startDragEndpoint);
74345 context.on('enter.intro', function (mode) {
74346 if (mode.id !== 'select') {
74347 continueTo(updateLine);
74351 function continueTo(nextStep) {
74352 context.map().on('move.intro drawn.intro', null);
74353 context.history().on('change.intro', null);
74354 context.on('enter.intro', null);
74359 function startDragEndpoint() {
74360 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74361 return continueTo(updateLine);
74364 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74365 var box = pad(woodRoadDragEndpoint, padding, context);
74366 var startDragString = helpHtml('intro.lines.start_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch')) + helpHtml('intro.lines.drag_to_intersection');
74367 reveal(box, startDragString);
74368 context.map().on('move.intro drawn.intro', function () {
74369 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74370 return continueTo(updateLine);
74373 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74374 var box = pad(woodRoadDragEndpoint, padding, context);
74375 reveal(box, startDragString, {
74378 var entity = context.entity(woodRoadEndID);
74380 if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) <= 4) {
74381 continueTo(finishDragEndpoint);
74385 function continueTo(nextStep) {
74386 context.map().on('move.intro drawn.intro', null);
74391 function finishDragEndpoint() {
74392 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74393 return continueTo(updateLine);
74396 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74397 var box = pad(woodRoadDragEndpoint, padding, context);
74398 var finishDragString = helpHtml('intro.lines.spot_looks_good') + helpHtml('intro.lines.finish_drag_endpoint' + (context.lastPointerType() === 'mouse' ? '' : '_touch'));
74399 reveal(box, finishDragString);
74400 context.map().on('move.intro drawn.intro', function () {
74401 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74402 return continueTo(updateLine);
74405 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74406 var box = pad(woodRoadDragEndpoint, padding, context);
74407 reveal(box, finishDragString, {
74410 var entity = context.entity(woodRoadEndID);
74412 if (geoSphericalDistance(entity.loc, woodRoadDragEndpoint) > 4) {
74413 continueTo(startDragEndpoint);
74416 context.on('enter.intro', function () {
74417 continueTo(startDragMidpoint);
74420 function continueTo(nextStep) {
74421 context.map().on('move.intro drawn.intro', null);
74422 context.on('enter.intro', null);
74427 function startDragMidpoint() {
74428 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74429 return continueTo(updateLine);
74432 if (context.selectedIDs().indexOf(woodRoadID) === -1) {
74433 context.enter(modeSelect(context, [woodRoadID]));
74436 var padding = 80 * Math.pow(2, context.map().zoom() - 19);
74437 var box = pad(woodRoadDragMidpoint, padding, context);
74438 reveal(box, helpHtml('intro.lines.start_drag_midpoint'));
74439 context.map().on('move.intro drawn.intro', function () {
74440 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74441 return continueTo(updateLine);
74444 var padding = 80 * Math.pow(2, context.map().zoom() - 19);
74445 var box = pad(woodRoadDragMidpoint, padding, context);
74446 reveal(box, helpHtml('intro.lines.start_drag_midpoint'), {
74450 context.history().on('change.intro', function (changed) {
74451 if (changed.created().length === 1) {
74452 continueTo(continueDragMidpoint);
74455 context.on('enter.intro', function (mode) {
74456 if (mode.id !== 'select') {
74457 // keep Wood Road selected so midpoint triangles are drawn..
74458 context.enter(modeSelect(context, [woodRoadID]));
74462 function continueTo(nextStep) {
74463 context.map().on('move.intro drawn.intro', null);
74464 context.history().on('change.intro', null);
74465 context.on('enter.intro', null);
74470 function continueDragMidpoint() {
74471 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74472 return continueTo(updateLine);
74475 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74476 var box = pad(woodRoadDragEndpoint, padding, context);
74479 var advance = function advance() {
74480 context.history().checkpoint('doneUpdateLine');
74481 continueTo(deleteLines);
74484 reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
74485 buttonText: _t.html('intro.ok'),
74486 buttonCallback: advance
74488 context.map().on('move.intro drawn.intro', function () {
74489 if (!context.hasEntity(woodRoadID) || !context.hasEntity(woodRoadEndID)) {
74490 return continueTo(updateLine);
74493 var padding = 100 * Math.pow(2, context.map().zoom() - 19);
74494 var box = pad(woodRoadDragEndpoint, padding, context);
74496 reveal(box, helpHtml('intro.lines.continue_drag_midpoint'), {
74498 buttonText: _t.html('intro.ok'),
74499 buttonCallback: advance
74503 function continueTo(nextStep) {
74504 context.map().on('move.intro drawn.intro', null);
74509 function deleteLines() {
74510 context.history().reset('doneUpdateLine');
74511 context.enter(modeBrowse(context));
74513 if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74514 return chapter.restart();
74517 var msec = transitionTime(deleteLinesLoc, context.map().center());
74520 reveal(null, null, {
74525 context.map().centerZoomEase(deleteLinesLoc, 18, msec);
74526 timeout(function () {
74527 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74528 var box = pad(deleteLinesLoc, padding, context);
74532 var advance = function advance() {
74533 continueTo(rightClickIntersection);
74536 reveal(box, helpHtml('intro.lines.delete_lines', {
74537 street: _t('intro.graph.name.12th-avenue')
74539 buttonText: _t.html('intro.ok'),
74540 buttonCallback: advance
74542 context.map().on('move.intro drawn.intro', function () {
74543 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74544 var box = pad(deleteLinesLoc, padding, context);
74547 reveal(box, helpHtml('intro.lines.delete_lines', {
74548 street: _t('intro.graph.name.12th-avenue')
74551 buttonText: _t.html('intro.ok'),
74552 buttonCallback: advance
74555 context.history().on('change.intro', function () {
74556 timeout(function () {
74557 continueTo(deleteLines);
74558 }, 500); // after any transition (e.g. if user deleted intersection)
74562 function continueTo(nextStep) {
74563 context.map().on('move.intro drawn.intro', null);
74564 context.history().on('change.intro', null);
74569 function rightClickIntersection() {
74570 context.history().reset('doneUpdateLine');
74571 context.enter(modeBrowse(context));
74572 context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
74573 var rightClickString = helpHtml('intro.lines.split_street', {
74574 street1: _t('intro.graph.name.11th-avenue'),
74575 street2: _t('intro.graph.name.washington-street')
74576 }) + helpHtml('intro.lines.' + (context.lastPointerType() === 'mouse' ? 'rightclick_intersection' : 'edit_menu_intersection_touch'));
74577 timeout(function () {
74578 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74579 var box = pad(eleventhAvenueEnd, padding, context);
74580 reveal(box, rightClickString);
74581 context.map().on('move.intro drawn.intro', function () {
74582 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74583 var box = pad(eleventhAvenueEnd, padding, context);
74584 reveal(box, rightClickString, {
74588 context.on('enter.intro', function (mode) {
74589 if (mode.id !== 'select') return;
74590 var ids = context.selectedIDs();
74591 if (ids.length !== 1 || ids[0] !== eleventhAvenueEndID) return;
74592 timeout(function () {
74593 var node = selectMenuItem(context, 'split').node();
74595 continueTo(splitIntersection);
74596 }, 50); // after menu visible
74598 context.history().on('change.intro', function () {
74599 timeout(function () {
74600 continueTo(deleteLines);
74601 }, 300); // after any transition (e.g. if user deleted intersection)
74605 function continueTo(nextStep) {
74606 context.map().on('move.intro drawn.intro', null);
74607 context.on('enter.intro', null);
74608 context.history().on('change.intro', null);
74613 function splitIntersection() {
74614 if (!context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74615 return continueTo(deleteLines);
74618 var node = selectMenuItem(context, 'split').node();
74621 return continueTo(rightClickIntersection);
74624 var wasChanged = false;
74625 _washingtonSegmentID = null;
74626 reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
74627 street: _t('intro.graph.name.washington-street')
74631 context.map().on('move.intro drawn.intro', function () {
74632 var node = selectMenuItem(context, 'split').node();
74634 if (!wasChanged && !node) {
74635 return continueTo(rightClickIntersection);
74638 reveal('.edit-menu', helpHtml('intro.lines.split_intersection', {
74639 street: _t('intro.graph.name.washington-street')
74645 context.history().on('change.intro', function (changed) {
74647 timeout(function () {
74648 if (context.history().undoAnnotation() === _t('operations.split.annotation.line', {
74651 _washingtonSegmentID = changed.created()[0].id;
74652 continueTo(didSplit);
74654 _washingtonSegmentID = null;
74655 continueTo(retrySplit);
74657 }, 300); // after any transition (e.g. if user deleted intersection)
74660 function continueTo(nextStep) {
74661 context.map().on('move.intro drawn.intro', null);
74662 context.history().on('change.intro', null);
74667 function retrySplit() {
74668 context.enter(modeBrowse(context));
74669 context.map().centerZoomEase(eleventhAvenueEnd, 18, 500);
74671 var advance = function advance() {
74672 continueTo(rightClickIntersection);
74675 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74676 var box = pad(eleventhAvenueEnd, padding, context);
74677 reveal(box, helpHtml('intro.lines.retry_split'), {
74678 buttonText: _t.html('intro.ok'),
74679 buttonCallback: advance
74681 context.map().on('move.intro drawn.intro', function () {
74682 var padding = 60 * Math.pow(2, context.map().zoom() - 18);
74683 var box = pad(eleventhAvenueEnd, padding, context);
74684 reveal(box, helpHtml('intro.lines.retry_split'), {
74686 buttonText: _t.html('intro.ok'),
74687 buttonCallback: advance
74691 function continueTo(nextStep) {
74692 context.map().on('move.intro drawn.intro', null);
74697 function didSplit() {
74698 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74699 return continueTo(rightClickIntersection);
74702 var ids = context.selectedIDs();
74703 var string = 'intro.lines.did_split_' + (ids.length > 1 ? 'multi' : 'single');
74704 var street = _t('intro.graph.name.washington-street');
74705 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74706 var box = pad(twelfthAvenue, padding, context);
74707 box.width = box.width / 2;
74708 reveal(box, helpHtml(string, {
74714 timeout(function () {
74715 context.map().centerZoomEase(twelfthAvenue, 18, 500);
74716 context.map().on('move.intro drawn.intro', function () {
74717 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74718 var box = pad(twelfthAvenue, padding, context);
74719 box.width = box.width / 2;
74720 reveal(box, helpHtml(string, {
74727 }, 600); // after initial reveal and curtain cut
74729 context.on('enter.intro', function () {
74730 var ids = context.selectedIDs();
74732 if (ids.length === 1 && ids[0] === _washingtonSegmentID) {
74733 continueTo(multiSelect);
74736 context.history().on('change.intro', function () {
74737 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74738 return continueTo(rightClickIntersection);
74742 function continueTo(nextStep) {
74743 context.map().on('move.intro drawn.intro', null);
74744 context.on('enter.intro', null);
74745 context.history().on('change.intro', null);
74750 function multiSelect() {
74751 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74752 return continueTo(rightClickIntersection);
74755 var ids = context.selectedIDs();
74756 var hasWashington = ids.indexOf(_washingtonSegmentID) !== -1;
74757 var hasTwelfth = ids.indexOf(twelfthAvenueID) !== -1;
74759 if (hasWashington && hasTwelfth) {
74760 return continueTo(multiRightClick);
74761 } else if (!hasWashington && !hasTwelfth) {
74762 return continueTo(didSplit);
74765 context.map().centerZoomEase(twelfthAvenue, 18, 500);
74766 timeout(function () {
74767 var selected, other, padding, box;
74769 if (hasWashington) {
74770 selected = _t('intro.graph.name.washington-street');
74771 other = _t('intro.graph.name.12th-avenue');
74772 padding = 60 * Math.pow(2, context.map().zoom() - 18);
74773 box = pad(twelfthAvenueEnd, padding, context);
74776 selected = _t('intro.graph.name.12th-avenue');
74777 other = _t('intro.graph.name.washington-street');
74778 padding = 200 * Math.pow(2, context.map().zoom() - 18);
74779 box = pad(twelfthAvenue, padding, context);
74783 reveal(box, helpHtml('intro.lines.multi_select', {
74784 selected: selected,
74786 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
74787 selected: selected,
74790 context.map().on('move.intro drawn.intro', function () {
74791 if (hasWashington) {
74792 selected = _t('intro.graph.name.washington-street');
74793 other = _t('intro.graph.name.12th-avenue');
74794 padding = 60 * Math.pow(2, context.map().zoom() - 18);
74795 box = pad(twelfthAvenueEnd, padding, context);
74798 selected = _t('intro.graph.name.12th-avenue');
74799 other = _t('intro.graph.name.washington-street');
74800 padding = 200 * Math.pow(2, context.map().zoom() - 18);
74801 box = pad(twelfthAvenue, padding, context);
74805 reveal(box, helpHtml('intro.lines.multi_select', {
74806 selected: selected,
74808 }) + ' ' + helpHtml('intro.lines.add_to_selection_' + (context.lastPointerType() === 'mouse' ? 'click' : 'touch'), {
74809 selected: selected,
74815 context.on('enter.intro', function () {
74816 continueTo(multiSelect);
74818 context.history().on('change.intro', function () {
74819 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74820 return continueTo(rightClickIntersection);
74825 function continueTo(nextStep) {
74826 context.map().on('move.intro drawn.intro', null);
74827 context.on('enter.intro', null);
74828 context.history().on('change.intro', null);
74833 function multiRightClick() {
74834 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74835 return continueTo(rightClickIntersection);
74838 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74839 var box = pad(twelfthAvenue, padding, context);
74840 var rightClickString = helpHtml('intro.lines.multi_select_success') + helpHtml('intro.lines.multi_' + (context.lastPointerType() === 'mouse' ? 'rightclick' : 'edit_menu_touch'));
74841 reveal(box, rightClickString);
74842 context.map().on('move.intro drawn.intro', function () {
74843 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74844 var box = pad(twelfthAvenue, padding, context);
74845 reveal(box, rightClickString, {
74849 context.ui().editMenu().on('toggled.intro', function (open) {
74851 timeout(function () {
74852 var ids = context.selectedIDs();
74854 if (ids.length === 2 && ids.indexOf(twelfthAvenueID) !== -1 && ids.indexOf(_washingtonSegmentID) !== -1) {
74855 var node = selectMenuItem(context, 'delete').node();
74857 continueTo(multiDelete);
74858 } else if (ids.length === 1 && ids.indexOf(_washingtonSegmentID) !== -1) {
74859 return continueTo(multiSelect);
74861 return continueTo(didSplit);
74863 }, 300); // after edit menu visible
74865 context.history().on('change.intro', function () {
74866 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74867 return continueTo(rightClickIntersection);
74871 function continueTo(nextStep) {
74872 context.map().on('move.intro drawn.intro', null);
74873 context.ui().editMenu().on('toggled.intro', null);
74874 context.history().on('change.intro', null);
74879 function multiDelete() {
74880 if (!_washingtonSegmentID || !context.hasEntity(_washingtonSegmentID) || !context.hasEntity(washingtonStreetID) || !context.hasEntity(twelfthAvenueID) || !context.hasEntity(eleventhAvenueEndID)) {
74881 return continueTo(rightClickIntersection);
74884 var node = selectMenuItem(context, 'delete').node();
74885 if (!node) return continueTo(multiRightClick);
74886 reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
74889 context.map().on('move.intro drawn.intro', function () {
74890 reveal('.edit-menu', helpHtml('intro.lines.multi_delete'), {
74895 context.on('exit.intro', function () {
74896 if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
74897 return continueTo(multiSelect); // left select mode but roads still exist
74900 context.history().on('change.intro', function () {
74901 if (context.hasEntity(_washingtonSegmentID) || context.hasEntity(twelfthAvenueID)) {
74902 continueTo(retryDelete); // changed something but roads still exist
74908 function continueTo(nextStep) {
74909 context.map().on('move.intro drawn.intro', null);
74910 context.on('exit.intro', null);
74911 context.history().on('change.intro', null);
74916 function retryDelete() {
74917 context.enter(modeBrowse(context));
74918 var padding = 200 * Math.pow(2, context.map().zoom() - 18);
74919 var box = pad(twelfthAvenue, padding, context);
74920 reveal(box, helpHtml('intro.lines.retry_delete'), {
74921 buttonText: _t.html('intro.ok'),
74922 buttonCallback: function buttonCallback() {
74923 continueTo(multiSelect);
74927 function continueTo(nextStep) {
74933 dispatch.call('done');
74934 reveal('.ideditor', helpHtml('intro.lines.play', {
74935 next: _t('intro.buildings.title')
74937 tooltipBox: '.intro-nav-wrap .chapter-building',
74938 buttonText: _t.html('intro.ok'),
74939 buttonCallback: function buttonCallback() {
74940 reveal('.ideditor');
74945 chapter.enter = function () {
74949 chapter.exit = function () {
74950 timeouts.forEach(window.clearTimeout);
74951 select(window).on('pointerdown.intro mousedown.intro', null, true);
74952 context.on('enter.intro exit.intro', null);
74953 context.map().on('move.intro drawn.intro', null);
74954 context.history().on('change.intro', null);
74955 context.container().select('.inspector-wrap').on('wheel.intro', null);
74956 context.container().select('.preset-list-button').on('click.intro', null);
74959 chapter.restart = function () {
74964 return utilRebind(chapter, dispatch, 'on');
74967 function uiIntroBuilding(context, reveal) {
74968 var dispatch = dispatch$8('done');
74969 var house = [-85.62815, 41.95638];
74970 var tank = [-85.62732, 41.95347];
74971 var buildingCatetory = _mainPresetIndex.item('category-building');
74972 var housePreset = _mainPresetIndex.item('building/house');
74973 var tankPreset = _mainPresetIndex.item('man_made/storage_tank');
74975 var _houseID = null;
74976 var _tankID = null;
74978 title: 'intro.buildings.title'
74981 function timeout(f, t) {
74982 timeouts.push(window.setTimeout(f, t));
74985 function eventCancel(d3_event) {
74986 d3_event.stopPropagation();
74987 d3_event.preventDefault();
74990 function revealHouse(center, text, options) {
74991 var padding = 160 * Math.pow(2, context.map().zoom() - 20);
74992 var box = pad(center, padding, context);
74993 reveal(box, text, options);
74996 function revealTank(center, text, options) {
74997 var padding = 190 * Math.pow(2, context.map().zoom() - 19.5);
74998 var box = pad(center, padding, context);
74999 reveal(box, text, options);
75002 function addHouse() {
75003 context.enter(modeBrowse(context));
75004 context.history().reset('initial');
75006 var msec = transitionTime(house, context.map().center());
75009 reveal(null, null, {
75014 context.map().centerZoomEase(house, 19, msec);
75015 timeout(function () {
75016 var tooltip = reveal('button.add-area', helpHtml('intro.buildings.add_building'));
75017 tooltip.selectAll('.popover-inner').insert('svg', 'span').attr('class', 'tooltip-illustration').append('use').attr('xlink:href', '#iD-graphic-buildings');
75018 context.on('enter.intro', function (mode) {
75019 if (mode.id !== 'add-area') return;
75020 continueTo(startHouse);
75024 function continueTo(nextStep) {
75025 context.on('enter.intro', null);
75030 function startHouse() {
75031 if (context.mode().id !== 'add-area') {
75032 return continueTo(addHouse);
75036 context.map().zoomEase(20, 500);
75037 timeout(function () {
75038 var startString = helpHtml('intro.buildings.start_building') + helpHtml('intro.buildings.building_corner_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
75039 revealHouse(house, startString);
75040 context.map().on('move.intro drawn.intro', function () {
75041 revealHouse(house, startString, {
75045 context.on('enter.intro', function (mode) {
75046 if (mode.id !== 'draw-area') return chapter.restart();
75047 continueTo(continueHouse);
75049 }, 550); // after easing
75051 function continueTo(nextStep) {
75052 context.map().on('move.intro drawn.intro', null);
75053 context.on('enter.intro', null);
75058 function continueHouse() {
75059 if (context.mode().id !== 'draw-area') {
75060 return continueTo(addHouse);
75064 var continueString = helpHtml('intro.buildings.continue_building') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_building');
75065 revealHouse(house, continueString);
75066 context.map().on('move.intro drawn.intro', function () {
75067 revealHouse(house, continueString, {
75071 context.on('enter.intro', function (mode) {
75072 if (mode.id === 'draw-area') {
75074 } else if (mode.id === 'select') {
75075 var graph = context.graph();
75076 var way = context.entity(context.selectedIDs()[0]);
75077 var nodes = graph.childNodes(way);
75078 var points = utilArrayUniq(nodes).map(function (n) {
75079 return context.projection(n.loc);
75082 if (isMostlySquare(points)) {
75084 return continueTo(chooseCategoryBuilding);
75086 return continueTo(retryHouse);
75089 return chapter.restart();
75093 function continueTo(nextStep) {
75094 context.map().on('move.intro drawn.intro', null);
75095 context.on('enter.intro', null);
75100 function retryHouse() {
75101 var onClick = function onClick() {
75102 continueTo(addHouse);
75105 revealHouse(house, helpHtml('intro.buildings.retry_building'), {
75106 buttonText: _t.html('intro.ok'),
75107 buttonCallback: onClick
75109 context.map().on('move.intro drawn.intro', function () {
75110 revealHouse(house, helpHtml('intro.buildings.retry_building'), {
75112 buttonText: _t.html('intro.ok'),
75113 buttonCallback: onClick
75117 function continueTo(nextStep) {
75118 context.map().on('move.intro drawn.intro', null);
75123 function chooseCategoryBuilding() {
75124 if (!_houseID || !context.hasEntity(_houseID)) {
75128 var ids = context.selectedIDs();
75130 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75131 context.enter(modeSelect(context, [_houseID]));
75132 } // disallow scrolling
75135 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75136 timeout(function () {
75137 // reset pane, in case user somehow happened to change it..
75138 context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75139 var button = context.container().select('.preset-category-building .preset-list-button');
75140 reveal(button.node(), helpHtml('intro.buildings.choose_category_building', {
75141 category: buildingCatetory.name()
75143 button.on('click.intro', function () {
75144 button.on('click.intro', null);
75145 continueTo(choosePresetHouse);
75147 }, 400); // after preset list pane visible..
75149 context.on('enter.intro', function (mode) {
75150 if (!_houseID || !context.hasEntity(_houseID)) {
75151 return continueTo(addHouse);
75154 var ids = context.selectedIDs();
75156 if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
75157 return continueTo(chooseCategoryBuilding);
75161 function continueTo(nextStep) {
75162 context.container().select('.inspector-wrap').on('wheel.intro', null);
75163 context.container().select('.preset-list-button').on('click.intro', null);
75164 context.on('enter.intro', null);
75169 function choosePresetHouse() {
75170 if (!_houseID || !context.hasEntity(_houseID)) {
75174 var ids = context.selectedIDs();
75176 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75177 context.enter(modeSelect(context, [_houseID]));
75178 } // disallow scrolling
75181 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75182 timeout(function () {
75183 // reset pane, in case user somehow happened to change it..
75184 context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75185 var button = context.container().select('.preset-building-house .preset-list-button');
75186 reveal(button.node(), helpHtml('intro.buildings.choose_preset_house', {
75187 preset: housePreset.name()
75191 button.on('click.intro', function () {
75192 button.on('click.intro', null);
75193 continueTo(closeEditorHouse);
75195 }, 400); // after preset list pane visible..
75197 context.on('enter.intro', function (mode) {
75198 if (!_houseID || !context.hasEntity(_houseID)) {
75199 return continueTo(addHouse);
75202 var ids = context.selectedIDs();
75204 if (mode.id !== 'select' || !ids.length || ids[0] !== _houseID) {
75205 return continueTo(chooseCategoryBuilding);
75209 function continueTo(nextStep) {
75210 context.container().select('.inspector-wrap').on('wheel.intro', null);
75211 context.container().select('.preset-list-button').on('click.intro', null);
75212 context.on('enter.intro', null);
75217 function closeEditorHouse() {
75218 if (!_houseID || !context.hasEntity(_houseID)) {
75222 var ids = context.selectedIDs();
75224 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _houseID) {
75225 context.enter(modeSelect(context, [_houseID]));
75228 context.history().checkpoint('hasHouse');
75229 context.on('exit.intro', function () {
75230 continueTo(rightClickHouse);
75232 timeout(function () {
75233 reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
75234 button: icon('#iD-icon-close', 'inline')
75238 function continueTo(nextStep) {
75239 context.on('exit.intro', null);
75244 function rightClickHouse() {
75245 if (!_houseID) return chapter.restart();
75246 context.enter(modeBrowse(context));
75247 context.history().reset('hasHouse');
75248 var zoom = context.map().zoom();
75254 context.map().centerZoomEase(house, zoom, 500);
75255 context.on('enter.intro', function (mode) {
75256 if (mode.id !== 'select') return;
75257 var ids = context.selectedIDs();
75258 if (ids.length !== 1 || ids[0] !== _houseID) return;
75259 timeout(function () {
75260 var node = selectMenuItem(context, 'orthogonalize').node();
75262 continueTo(clickSquare);
75263 }, 50); // after menu visible
75265 context.map().on('move.intro drawn.intro', function () {
75266 var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_building' : 'edit_menu_building_touch'));
75267 revealHouse(house, rightclickString, {
75271 context.history().on('change.intro', function () {
75272 continueTo(rightClickHouse);
75275 function continueTo(nextStep) {
75276 context.on('enter.intro', null);
75277 context.map().on('move.intro drawn.intro', null);
75278 context.history().on('change.intro', null);
75283 function clickSquare() {
75284 if (!_houseID) return chapter.restart();
75285 var entity = context.hasEntity(_houseID);
75286 if (!entity) return continueTo(rightClickHouse);
75287 var node = selectMenuItem(context, 'orthogonalize').node();
75290 return continueTo(rightClickHouse);
75293 var wasChanged = false;
75294 reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
75297 context.on('enter.intro', function (mode) {
75298 if (mode.id === 'browse') {
75299 continueTo(rightClickHouse);
75300 } else if (mode.id === 'move' || mode.id === 'rotate') {
75301 continueTo(retryClickSquare);
75304 context.map().on('move.intro', function () {
75305 var node = selectMenuItem(context, 'orthogonalize').node();
75307 if (!wasChanged && !node) {
75308 return continueTo(rightClickHouse);
75311 reveal('.edit-menu', helpHtml('intro.buildings.square_building'), {
75316 context.history().on('change.intro', function () {
75318 context.history().on('change.intro', null); // Something changed. Wait for transition to complete and check undo annotation.
75320 timeout(function () {
75321 if (context.history().undoAnnotation() === _t('operations.orthogonalize.annotation.feature', {
75324 continueTo(doneSquare);
75326 continueTo(retryClickSquare);
75328 }, 500); // after transitioned actions
75331 function continueTo(nextStep) {
75332 context.on('enter.intro', null);
75333 context.map().on('move.intro', null);
75334 context.history().on('change.intro', null);
75339 function retryClickSquare() {
75340 context.enter(modeBrowse(context));
75341 revealHouse(house, helpHtml('intro.buildings.retry_square'), {
75342 buttonText: _t.html('intro.ok'),
75343 buttonCallback: function buttonCallback() {
75344 continueTo(rightClickHouse);
75348 function continueTo(nextStep) {
75353 function doneSquare() {
75354 context.history().checkpoint('doneSquare');
75355 revealHouse(house, helpHtml('intro.buildings.done_square'), {
75356 buttonText: _t.html('intro.ok'),
75357 buttonCallback: function buttonCallback() {
75358 continueTo(addTank);
75362 function continueTo(nextStep) {
75367 function addTank() {
75368 context.enter(modeBrowse(context));
75369 context.history().reset('doneSquare');
75371 var msec = transitionTime(tank, context.map().center());
75374 reveal(null, null, {
75379 context.map().centerZoomEase(tank, 19.5, msec);
75380 timeout(function () {
75381 reveal('button.add-area', helpHtml('intro.buildings.add_tank'));
75382 context.on('enter.intro', function (mode) {
75383 if (mode.id !== 'add-area') return;
75384 continueTo(startTank);
75388 function continueTo(nextStep) {
75389 context.on('enter.intro', null);
75394 function startTank() {
75395 if (context.mode().id !== 'add-area') {
75396 return continueTo(addTank);
75400 timeout(function () {
75401 var startString = helpHtml('intro.buildings.start_tank') + helpHtml('intro.buildings.tank_edge_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap'));
75402 revealTank(tank, startString);
75403 context.map().on('move.intro drawn.intro', function () {
75404 revealTank(tank, startString, {
75408 context.on('enter.intro', function (mode) {
75409 if (mode.id !== 'draw-area') return chapter.restart();
75410 continueTo(continueTank);
75412 }, 550); // after easing
75414 function continueTo(nextStep) {
75415 context.map().on('move.intro drawn.intro', null);
75416 context.on('enter.intro', null);
75421 function continueTank() {
75422 if (context.mode().id !== 'draw-area') {
75423 return continueTo(addTank);
75427 var continueString = helpHtml('intro.buildings.continue_tank') + '{br}' + helpHtml('intro.areas.finish_area_' + (context.lastPointerType() === 'mouse' ? 'click' : 'tap')) + helpHtml('intro.buildings.finish_tank');
75428 revealTank(tank, continueString);
75429 context.map().on('move.intro drawn.intro', function () {
75430 revealTank(tank, continueString, {
75434 context.on('enter.intro', function (mode) {
75435 if (mode.id === 'draw-area') {
75437 } else if (mode.id === 'select') {
75438 _tankID = context.selectedIDs()[0];
75439 return continueTo(searchPresetTank);
75441 return continueTo(addTank);
75445 function continueTo(nextStep) {
75446 context.map().on('move.intro drawn.intro', null);
75447 context.on('enter.intro', null);
75452 function searchPresetTank() {
75453 if (!_tankID || !context.hasEntity(_tankID)) {
75457 var ids = context.selectedIDs();
75459 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
75460 context.enter(modeSelect(context, [_tankID]));
75461 } // disallow scrolling
75464 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75465 timeout(function () {
75466 // reset pane, in case user somehow happened to change it..
75467 context.container().select('.inspector-wrap .panewrap').style('right', '-100%');
75468 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
75469 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
75470 preset: tankPreset.name()
75472 }, 400); // after preset list pane visible..
75474 context.on('enter.intro', function (mode) {
75475 if (!_tankID || !context.hasEntity(_tankID)) {
75476 return continueTo(addTank);
75479 var ids = context.selectedIDs();
75481 if (mode.id !== 'select' || !ids.length || ids[0] !== _tankID) {
75482 // keep the user's area selected..
75483 context.enter(modeSelect(context, [_tankID])); // reset pane, in case user somehow happened to change it..
75485 context.container().select('.inspector-wrap .panewrap').style('right', '-100%'); // disallow scrolling
75487 context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
75488 context.container().select('.preset-search-input').on('keydown.intro', null).on('keyup.intro', checkPresetSearch);
75489 reveal('.preset-search-input', helpHtml('intro.buildings.search_tank', {
75490 preset: tankPreset.name()
75492 context.history().on('change.intro', null);
75496 function checkPresetSearch() {
75497 var first = context.container().select('.preset-list-item:first-child');
75499 if (first.classed('preset-man_made-storage_tank')) {
75500 reveal(first.select('.preset-list-button').node(), helpHtml('intro.buildings.choose_tank', {
75501 preset: tankPreset.name()
75505 context.container().select('.preset-search-input').on('keydown.intro', eventCancel, true).on('keyup.intro', null);
75506 context.history().on('change.intro', function () {
75507 continueTo(closeEditorTank);
75512 function continueTo(nextStep) {
75513 context.container().select('.inspector-wrap').on('wheel.intro', null);
75514 context.on('enter.intro', null);
75515 context.history().on('change.intro', null);
75516 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
75521 function closeEditorTank() {
75522 if (!_tankID || !context.hasEntity(_tankID)) {
75526 var ids = context.selectedIDs();
75528 if (context.mode().id !== 'select' || !ids.length || ids[0] !== _tankID) {
75529 context.enter(modeSelect(context, [_tankID]));
75532 context.history().checkpoint('hasTank');
75533 context.on('exit.intro', function () {
75534 continueTo(rightClickTank);
75536 timeout(function () {
75537 reveal('.entity-editor-pane', helpHtml('intro.buildings.close', {
75538 button: icon('#iD-icon-close', 'inline')
75542 function continueTo(nextStep) {
75543 context.on('exit.intro', null);
75548 function rightClickTank() {
75549 if (!_tankID) return continueTo(addTank);
75550 context.enter(modeBrowse(context));
75551 context.history().reset('hasTank');
75552 context.map().centerEase(tank, 500);
75553 timeout(function () {
75554 context.on('enter.intro', function (mode) {
75555 if (mode.id !== 'select') return;
75556 var ids = context.selectedIDs();
75557 if (ids.length !== 1 || ids[0] !== _tankID) return;
75558 timeout(function () {
75559 var node = selectMenuItem(context, 'circularize').node();
75561 continueTo(clickCircle);
75562 }, 50); // after menu visible
75564 var rightclickString = helpHtml('intro.buildings.' + (context.lastPointerType() === 'mouse' ? 'rightclick_tank' : 'edit_menu_tank_touch'));
75565 revealTank(tank, rightclickString);
75566 context.map().on('move.intro drawn.intro', function () {
75567 revealTank(tank, rightclickString, {
75571 context.history().on('change.intro', function () {
75572 continueTo(rightClickTank);
75576 function continueTo(nextStep) {
75577 context.on('enter.intro', null);
75578 context.map().on('move.intro drawn.intro', null);
75579 context.history().on('change.intro', null);
75584 function clickCircle() {
75585 if (!_tankID) return chapter.restart();
75586 var entity = context.hasEntity(_tankID);
75587 if (!entity) return continueTo(rightClickTank);
75588 var node = selectMenuItem(context, 'circularize').node();
75591 return continueTo(rightClickTank);
75594 var wasChanged = false;
75595 reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
75598 context.on('enter.intro', function (mode) {
75599 if (mode.id === 'browse') {
75600 continueTo(rightClickTank);
75601 } else if (mode.id === 'move' || mode.id === 'rotate') {
75602 continueTo(retryClickCircle);
75605 context.map().on('move.intro', function () {
75606 var node = selectMenuItem(context, 'circularize').node();
75608 if (!wasChanged && !node) {
75609 return continueTo(rightClickTank);
75612 reveal('.edit-menu', helpHtml('intro.buildings.circle_tank'), {
75617 context.history().on('change.intro', function () {
75619 context.history().on('change.intro', null); // Something changed. Wait for transition to complete and check undo annotation.
75621 timeout(function () {
75622 if (context.history().undoAnnotation() === _t('operations.circularize.annotation.feature', {
75627 continueTo(retryClickCircle);
75629 }, 500); // after transitioned actions
75632 function continueTo(nextStep) {
75633 context.on('enter.intro', null);
75634 context.map().on('move.intro', null);
75635 context.history().on('change.intro', null);
75640 function retryClickCircle() {
75641 context.enter(modeBrowse(context));
75642 revealTank(tank, helpHtml('intro.buildings.retry_circle'), {
75643 buttonText: _t.html('intro.ok'),
75644 buttonCallback: function buttonCallback() {
75645 continueTo(rightClickTank);
75649 function continueTo(nextStep) {
75655 dispatch.call('done');
75656 reveal('.ideditor', helpHtml('intro.buildings.play', {
75657 next: _t('intro.startediting.title')
75659 tooltipBox: '.intro-nav-wrap .chapter-startEditing',
75660 buttonText: _t.html('intro.ok'),
75661 buttonCallback: function buttonCallback() {
75662 reveal('.ideditor');
75667 chapter.enter = function () {
75671 chapter.exit = function () {
75672 timeouts.forEach(window.clearTimeout);
75673 context.on('enter.intro exit.intro', null);
75674 context.map().on('move.intro drawn.intro', null);
75675 context.history().on('change.intro', null);
75676 context.container().select('.inspector-wrap').on('wheel.intro', null);
75677 context.container().select('.preset-search-input').on('keydown.intro keyup.intro', null);
75678 context.container().select('.more-fields .combobox-input').on('click.intro', null);
75681 chapter.restart = function () {
75686 return utilRebind(chapter, dispatch, 'on');
75689 function uiIntroStartEditing(context, reveal) {
75690 var dispatch = dispatch$8('done', 'startEditing');
75691 var modalSelection = select(null);
75693 title: 'intro.startediting.title'
75696 function showHelp() {
75697 reveal('.map-control.help-control', helpHtml('intro.startediting.help'), {
75698 buttonText: _t.html('intro.ok'),
75699 buttonCallback: function buttonCallback() {
75705 function shortcuts() {
75706 reveal('.map-control.help-control', helpHtml('intro.startediting.shortcuts'), {
75707 buttonText: _t.html('intro.ok'),
75708 buttonCallback: function buttonCallback() {
75714 function showSave() {
75715 context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75717 reveal('.top-toolbar button.save', helpHtml('intro.startediting.save'), {
75718 buttonText: _t.html('intro.ok'),
75719 buttonCallback: function buttonCallback() {
75725 function showStart() {
75726 context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75728 modalSelection = uiModal(context.container());
75729 modalSelection.select('.modal').attr('class', 'modal-splash modal');
75730 modalSelection.selectAll('.close').remove();
75731 var startbutton = modalSelection.select('.content').attr('class', 'fillL').append('button').attr('class', 'modal-section huge-modal-button').on('click', function () {
75732 modalSelection.remove();
75734 startbutton.append('svg').attr('class', 'illustration').append('use').attr('xlink:href', '#iD-logo-walkthrough');
75735 startbutton.append('h2').html(_t.html('intro.startediting.start'));
75736 dispatch.call('startEditing');
75739 chapter.enter = function () {
75743 chapter.exit = function () {
75744 modalSelection.remove();
75745 context.container().selectAll('.shaded').remove(); // in case user opened keyboard shortcuts
75748 return utilRebind(chapter, dispatch, 'on');
75752 welcome: uiIntroWelcome,
75753 navigation: uiIntroNavigation,
75754 point: uiIntroPoint,
75757 building: uiIntroBuilding,
75758 startEditing: uiIntroStartEditing
75760 var chapterFlow = ['welcome', 'navigation', 'point', 'area', 'line', 'building', 'startEditing'];
75761 function uiIntro(context) {
75762 var INTRO_IMAGERY = 'EsriWorldImageryClarity';
75763 var _introGraph = {};
75767 function intro(selection) {
75768 _mainFileFetcher.get('intro_graph').then(function (dataIntroGraph) {
75769 // create entities for intro graph and localize names
75770 for (var id in dataIntroGraph) {
75771 if (!_introGraph[id]) {
75772 _introGraph[id] = osmEntity(localize(dataIntroGraph[id]));
75776 selection.call(startIntro);
75777 })["catch"](function () {
75782 function startIntro(selection) {
75783 context.enter(modeBrowse(context)); // Save current map state
75785 var osm = context.connection();
75786 var history = context.history().toJSON();
75787 var hash = window.location.hash;
75788 var center = context.map().center();
75789 var zoom = context.map().zoom();
75790 var background = context.background().baseLayerSource();
75791 var overlays = context.background().overlayLayerSources();
75792 var opacity = context.container().selectAll('.main-map .layer-background').style('opacity');
75793 var caches = osm && osm.caches();
75794 var baseEntities = context.history().graph().base().entities; // Show sidebar and disable the sidebar resizing button
75795 // (this needs to be before `context.inIntro(true)`)
75797 context.ui().sidebar.expand();
75798 context.container().selectAll('button.sidebar-toggle').classed('disabled', true); // Block saving
75800 context.inIntro(true); // Load semi-real data used in intro
75803 osm.toggle(false).reset();
75806 context.history().reset();
75807 context.history().merge(Object.values(coreGraph().load(_introGraph).entities));
75808 context.history().checkpoint('initial'); // Setup imagery
75810 var imagery = context.background().findSource(INTRO_IMAGERY);
75813 context.background().baseLayerSource(imagery);
75815 context.background().bing();
75818 overlays.forEach(function (d) {
75819 return context.background().toggleOverlayLayer(d);
75820 }); // Setup data layers (only OSM)
75822 var layers = context.layers();
75823 layers.all().forEach(function (item) {
75824 // if the layer has the function `enabled`
75825 if (typeof item.layer.enabled === 'function') {
75826 item.layer.enabled(item.id === 'osm');
75829 context.container().selectAll('.main-map .layer-background').style('opacity', 1);
75830 var curtain = uiCurtain(context.container().node());
75831 selection.call(curtain); // Store that the user started the walkthrough..
75833 corePreferences('walkthrough_started', 'yes'); // Restore previous walkthrough progress..
75835 var storedProgress = corePreferences('walkthrough_progress') || '';
75836 var progress = storedProgress.split(';').filter(Boolean);
75837 var chapters = chapterFlow.map(function (chapter, i) {
75838 var s = chapterUi[chapter](context, curtain.reveal).on('done', function () {
75839 buttons.filter(function (d) {
75840 return d.title === s.title;
75841 }).classed('finished', true);
75843 if (i < chapterFlow.length - 1) {
75844 var next = chapterFlow[i + 1];
75845 context.container().select("button.chapter-".concat(next)).classed('next', true);
75846 } // Store walkthrough progress..
75849 progress.push(chapter);
75850 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';'));
75854 chapters[chapters.length - 1].on('startEditing', function () {
75855 // Store walkthrough progress..
75856 progress.push('startEditing');
75857 corePreferences('walkthrough_progress', utilArrayUniq(progress).join(';')); // Store if walkthrough is completed..
75859 var incomplete = utilArrayDifference(chapterFlow, progress);
75861 if (!incomplete.length) {
75862 corePreferences('walkthrough_completed', 'yes');
75867 context.container().selectAll('.main-map .layer-background').style('opacity', opacity);
75868 context.container().selectAll('button.sidebar-toggle').classed('disabled', false);
75871 osm.toggle(true).reset().caches(caches);
75874 context.history().reset().merge(Object.values(baseEntities));
75875 context.background().baseLayerSource(background);
75876 overlays.forEach(function (d) {
75877 return context.background().toggleOverlayLayer(d);
75881 context.history().fromJSON(history, false);
75884 context.map().centerZoom(center, zoom);
75885 window.location.replace(hash);
75886 context.inIntro(false);
75888 var navwrap = selection.append('div').attr('class', 'intro-nav-wrap fillD');
75889 navwrap.append('svg').attr('class', 'intro-nav-wrap-logo').append('use').attr('xlink:href', '#iD-logo-walkthrough');
75890 var buttonwrap = navwrap.append('div').attr('class', 'joined').selectAll('button.chapter');
75891 var buttons = buttonwrap.data(chapters).enter().append('button').attr('class', function (d, i) {
75892 return "chapter chapter-".concat(chapterFlow[i]);
75893 }).on('click', enterChapter);
75894 buttons.append('span').html(function (d) {
75895 return _t.html(d.title);
75897 buttons.append('span').attr('class', 'status').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
75898 enterChapter(null, chapters[0]);
75900 function enterChapter(d3_event, newChapter) {
75901 if (_currChapter) {
75902 _currChapter.exit();
75905 context.enter(modeBrowse(context));
75906 _currChapter = newChapter;
75908 _currChapter.enter();
75910 buttons.classed('next', false).classed('active', function (d) {
75911 return d.title === _currChapter.title;
75919 function uiIssuesInfo(context) {
75920 var warningsItem = {
75923 iconID: 'iD-icon-alert',
75924 descriptionID: 'issues.warnings_and_errors'
75926 var resolvedItem = {
75929 iconID: 'iD-icon-apply',
75930 descriptionID: 'issues.user_resolved_issues'
75933 function update(selection) {
75934 var shownItems = [];
75935 var liveIssues = context.validator().getIssues({
75936 what: corePreferences('validate-what') || 'edited',
75937 where: corePreferences('validate-where') || 'all'
75940 if (liveIssues.length) {
75941 warningsItem.count = liveIssues.length;
75942 shownItems.push(warningsItem);
75945 if (corePreferences('validate-what') === 'all') {
75946 var resolvedIssues = context.validator().getResolvedIssues();
75948 if (resolvedIssues.length) {
75949 resolvedItem.count = resolvedIssues.length;
75950 shownItems.push(resolvedItem);
75954 var chips = selection.selectAll('.chip').data(shownItems, function (d) {
75957 chips.exit().remove();
75958 var enter = chips.enter().append('a').attr('class', function (d) {
75959 return 'chip ' + d.id + '-count';
75960 }).attr('href', '#').each(function (d) {
75961 var chipSelection = select(this);
75962 var tooltipBehavior = uiTooltip().placement('top').title(_t.html(d.descriptionID));
75963 chipSelection.call(tooltipBehavior).on('click', function (d3_event) {
75964 d3_event.preventDefault();
75965 tooltipBehavior.hide(select(this)); // open the Issues pane
75967 context.ui().togglePanes(context.container().select('.map-panes .issues-pane'));
75969 chipSelection.call(svgIcon('#' + d.iconID));
75971 enter.append('span').attr('class', 'count');
75972 enter.merge(chips).selectAll('span.count').html(function (d) {
75973 return d.count.toString();
75977 return function (selection) {
75979 context.validator().on('validated.infobox', function () {
75985 function uiMapInMap(context) {
75986 function mapInMap(selection) {
75987 var backgroundLayer = rendererTileLayer(context);
75988 var overlayLayers = {};
75989 var projection = geoRawMercator();
75990 var dataLayer = svgData(projection, context).showLabels(false);
75991 var debugLayer = svgDebug(projection, context);
75992 var zoom = d3_zoom().scaleExtent([geoZoomToScale(0.5), geoZoomToScale(24)]).on('start', zoomStarted).on('zoom', zoomed).on('end', zoomEnded);
75993 var wrap = select(null);
75994 var tiles = select(null);
75995 var viewport = select(null);
75996 var _isTransformed = false;
75997 var _isHidden = true;
75998 var _skipEvents = false;
75999 var _gesture = null;
76000 var _zDiff = 6; // by default, minimap renders at (main zoom - 6)
76002 var _dMini; // dimensions of minimap
76005 var _cMini; // center pixel of minimap
76008 var _tStart; // transform at start of gesture
76011 var _tCurr; // transform at most recent event
76016 function zoomStarted() {
76017 if (_skipEvents) return;
76018 _tStart = _tCurr = projection.transform();
76022 function zoomed(d3_event) {
76023 if (_skipEvents) return;
76024 var x = d3_event.transform.x;
76025 var y = d3_event.transform.y;
76026 var k = d3_event.transform.k;
76027 var isZooming = k !== _tStart.k;
76028 var isPanning = x !== _tStart.x || y !== _tStart.y;
76030 if (!isZooming && !isPanning) {
76031 return; // no change
76032 } // lock in either zooming or panning, don't allow both in minimap.
76036 _gesture = isZooming ? 'zoom' : 'pan';
76039 var tMini = projection.transform();
76042 if (_gesture === 'zoom') {
76043 scale = k / tMini.k;
76044 tX = (_cMini[0] / scale - _cMini[0]) * scale;
76045 tY = (_cMini[1] / scale - _cMini[1]) * scale;
76053 utilSetTransform(tiles, tX, tY, scale);
76054 utilSetTransform(viewport, 0, 0, scale);
76055 _isTransformed = true;
76056 _tCurr = identity$2.translate(x, y).scale(k);
76057 var zMain = geoScaleToZoom(context.projection.scale());
76058 var zMini = geoScaleToZoom(k);
76059 _zDiff = zMain - zMini;
76063 function zoomEnded() {
76064 if (_skipEvents) return;
76065 if (_gesture !== 'pan') return;
76066 updateProjection();
76068 context.map().center(projection.invert(_cMini)); // recenter main map..
76071 function updateProjection() {
76072 var loc = context.map().center();
76073 var tMain = context.projection.transform();
76074 var zMain = geoScaleToZoom(tMain.k);
76075 var zMini = Math.max(zMain - _zDiff, 0.5);
76076 var kMini = geoZoomToScale(zMini);
76077 projection.translate([tMain.x, tMain.y]).scale(kMini);
76078 var point = projection(loc);
76079 var mouse = _gesture === 'pan' ? geoVecSubtract([_tCurr.x, _tCurr.y], [_tStart.x, _tStart.y]) : [0, 0];
76080 var xMini = _cMini[0] - point[0] + tMain.x + mouse[0];
76081 var yMini = _cMini[1] - point[1] + tMain.y + mouse[1];
76082 projection.translate([xMini, yMini]).clipExtent([[0, 0], _dMini]);
76083 _tCurr = projection.transform();
76085 if (_isTransformed) {
76086 utilSetTransform(tiles, 0, 0);
76087 utilSetTransform(viewport, 0, 0);
76088 _isTransformed = false;
76091 zoom.scaleExtent([geoZoomToScale(0.5), geoZoomToScale(zMain - 3)]);
76092 _skipEvents = true;
76093 wrap.call(zoom.transform, _tCurr);
76094 _skipEvents = false;
76097 function redraw() {
76098 clearTimeout(_timeoutID);
76099 if (_isHidden) return;
76100 updateProjection();
76101 var zMini = geoScaleToZoom(projection.scale()); // setup tile container
76103 tiles = wrap.selectAll('.map-in-map-tiles').data([0]);
76104 tiles = tiles.enter().append('div').attr('class', 'map-in-map-tiles').merge(tiles); // redraw background
76106 backgroundLayer.source(context.background().baseLayerSource()).projection(projection).dimensions(_dMini);
76107 var background = tiles.selectAll('.map-in-map-background').data([0]);
76108 background.enter().append('div').attr('class', 'map-in-map-background').merge(background).call(backgroundLayer); // redraw overlay
76110 var overlaySources = context.background().overlayLayerSources();
76111 var activeOverlayLayers = [];
76113 for (var i = 0; i < overlaySources.length; i++) {
76114 if (overlaySources[i].validZoom(zMini)) {
76115 if (!overlayLayers[i]) overlayLayers[i] = rendererTileLayer(context);
76116 activeOverlayLayers.push(overlayLayers[i].source(overlaySources[i]).projection(projection).dimensions(_dMini));
76120 var overlay = tiles.selectAll('.map-in-map-overlay').data([0]);
76121 overlay = overlay.enter().append('div').attr('class', 'map-in-map-overlay').merge(overlay);
76122 var overlays = overlay.selectAll('div').data(activeOverlayLayers, function (d) {
76123 return d.source().name();
76125 overlays.exit().remove();
76126 overlays = overlays.enter().append('div').merge(overlays).each(function (layer) {
76127 select(this).call(layer);
76129 var dataLayers = tiles.selectAll('.map-in-map-data').data([0]);
76130 dataLayers.exit().remove();
76131 dataLayers = dataLayers.enter().append('svg').attr('class', 'map-in-map-data').merge(dataLayers).call(dataLayer).call(debugLayer); // redraw viewport bounding box
76133 if (_gesture !== 'pan') {
76134 var getPath = d3_geoPath(projection);
76137 coordinates: [context.map().extent().polygon()]
76139 viewport = wrap.selectAll('.map-in-map-viewport').data([0]);
76140 viewport = viewport.enter().append('svg').attr('class', 'map-in-map-viewport').merge(viewport);
76141 var path = viewport.selectAll('.map-in-map-bbox').data([bbox]);
76142 path.enter().append('path').attr('class', 'map-in-map-bbox').merge(path).attr('d', getPath).classed('thick', function (d) {
76143 return getPath.area(d) < 30;
76148 function queueRedraw() {
76149 clearTimeout(_timeoutID);
76150 _timeoutID = setTimeout(function () {
76155 function toggle(d3_event) {
76156 if (d3_event) d3_event.preventDefault();
76157 _isHidden = !_isHidden;
76158 context.container().select('.minimap-toggle-item').classed('active', !_isHidden).select('input').property('checked', !_isHidden);
76161 wrap.style('display', 'block').style('opacity', '1').transition().duration(200).style('opacity', '0').on('end', function () {
76162 selection.selectAll('.map-in-map').style('display', 'none');
76165 wrap.style('display', 'block').style('opacity', '0').transition().duration(200).style('opacity', '1').on('end', function () {
76171 uiMapInMap.toggle = toggle;
76172 wrap = selection.selectAll('.map-in-map').data([0]);
76173 wrap = wrap.enter().append('div').attr('class', 'map-in-map').style('display', _isHidden ? 'none' : 'block').call(zoom).on('dblclick.zoom', null).merge(wrap); // reflow warning: Hardcode dimensions - currently can't resize it anyway..
76175 _dMini = [200, 150]; //utilGetDimensions(wrap);
76177 _cMini = geoVecScale(_dMini, 0.5);
76178 context.map().on('drawn.map-in-map', function (drawn) {
76179 if (drawn.full === true) {
76184 context.keybinding().on(_t('background.minimap.key'), toggle);
76190 function uiNotice(context) {
76191 return function (selection) {
76192 var div = selection.append('div').attr('class', 'notice');
76193 var button = div.append('button').attr('class', 'zoom-to notice fillD').on('click', function () {
76194 context.map().zoomEase(context.minEditableZoom());
76195 }).on('wheel', function (d3_event) {
76196 // let wheel events pass through #4482
76197 var e2 = new WheelEvent(d3_event.type, d3_event);
76198 context.surface().node().dispatchEvent(e2);
76200 button.call(svgIcon('#iD-icon-plus', 'pre-text')).append('span').attr('class', 'label').html(_t.html('zoom_in_edit'));
76202 function disableTooHigh() {
76203 var canEdit = context.map().zoom() >= context.minEditableZoom();
76204 div.style('display', canEdit ? 'none' : 'block');
76207 context.map().on('move.notice', debounce(disableTooHigh, 500));
76212 function uiPhotoviewer(context) {
76213 var dispatch = dispatch$8('resize');
76215 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
76217 function photoviewer(selection) {
76218 selection.append('button').attr('class', 'thumb-hide').on('click', function () {
76219 if (services.streetside) {
76220 services.streetside.hideViewer(context);
76223 if (services.mapillary) {
76224 services.mapillary.hideViewer(context);
76227 if (services.openstreetcam) {
76228 services.openstreetcam.hideViewer(context);
76230 }).append('div').call(svgIcon('#iD-icon-close'));
76232 function preventDefault(d3_event) {
76233 d3_event.preventDefault();
76236 selection.append('button').attr('class', 'resize-handle-xy').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76240 selection.append('button').attr('class', 'resize-handle-x').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76243 selection.append('button').attr('class', 'resize-handle-y').on('touchstart touchdown touchend', preventDefault).on(_pointerPrefix + 'down', buildResizeListener(selection, 'resize', dispatch, {
76247 function buildResizeListener(target, eventName, dispatch, options) {
76248 var resizeOnX = !!options.resizeOnX;
76249 var resizeOnY = !!options.resizeOnY;
76250 var minHeight = options.minHeight || 240;
76251 var minWidth = options.minWidth || 320;
76258 function startResize(d3_event) {
76259 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
76260 d3_event.preventDefault();
76261 d3_event.stopPropagation();
76262 var mapSize = context.map().dimensions();
76265 var maxWidth = mapSize[0];
76266 var newWidth = clamp(startWidth + d3_event.clientX - startX, minWidth, maxWidth);
76267 target.style('width', newWidth + 'px');
76271 var maxHeight = mapSize[1] - 90; // preserve space at top/bottom of map
76273 var newHeight = clamp(startHeight + startY - d3_event.clientY, minHeight, maxHeight);
76274 target.style('height', newHeight + 'px');
76277 dispatch.call(eventName, target, utilGetDimensions(target, true));
76280 function clamp(num, min, max) {
76281 return Math.max(min, Math.min(num, max));
76284 function stopResize(d3_event) {
76285 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
76286 d3_event.preventDefault();
76287 d3_event.stopPropagation(); // remove all the listeners we added
76289 select(window).on('.' + eventName, null);
76292 return function initResize(d3_event) {
76293 d3_event.preventDefault();
76294 d3_event.stopPropagation();
76295 pointerId = d3_event.pointerId || 'mouse';
76296 startX = d3_event.clientX;
76297 startY = d3_event.clientY;
76298 var targetRect = target.node().getBoundingClientRect();
76299 startWidth = targetRect.width;
76300 startHeight = targetRect.height;
76301 select(window).on(_pointerPrefix + 'move.' + eventName, startResize, false).on(_pointerPrefix + 'up.' + eventName, stopResize, false);
76303 if (_pointerPrefix === 'pointer') {
76304 select(window).on('pointercancel.' + eventName, stopResize, false);
76310 photoviewer.onMapResize = function () {
76311 var photoviewer = context.container().select('.photoviewer');
76312 var content = context.container().select('.main-content');
76313 var mapDimensions = utilGetDimensions(content, true); // shrink photo viewer if it is too big
76314 // (-90 preserves space at top and bottom of map used by menus)
76316 var photoDimensions = utilGetDimensions(photoviewer, true);
76318 if (photoDimensions[0] > mapDimensions[0] || photoDimensions[1] > mapDimensions[1] - 90) {
76319 var setPhotoDimensions = [Math.min(photoDimensions[0], mapDimensions[0]), Math.min(photoDimensions[1], mapDimensions[1] - 90)];
76320 photoviewer.style('width', setPhotoDimensions[0] + 'px').style('height', setPhotoDimensions[1] + 'px');
76321 dispatch.call('resize', photoviewer, setPhotoDimensions);
76325 return utilRebind(photoviewer, dispatch, 'on');
76328 function uiRestore(context) {
76329 return function (selection) {
76330 if (!context.history().hasRestorableChanges()) return;
76331 var modalSelection = uiModal(selection, true);
76332 modalSelection.select('.modal').attr('class', 'modal fillL');
76333 var introModal = modalSelection.select('.content');
76334 introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('restore.heading'));
76335 introModal.append('div').attr('class', 'modal-section').append('p').html(_t.html('restore.description'));
76336 var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
76337 var restore = buttonWrap.append('button').attr('class', 'restore').on('click', function () {
76338 context.history().restore();
76339 modalSelection.remove();
76341 restore.append('svg').attr('class', 'logo logo-restore').append('use').attr('xlink:href', '#iD-logo-restore');
76342 restore.append('div').html(_t.html('restore.restore'));
76343 var reset = buttonWrap.append('button').attr('class', 'reset').on('click', function () {
76344 context.history().clearSaved();
76345 modalSelection.remove();
76347 reset.append('svg').attr('class', 'logo logo-reset').append('use').attr('xlink:href', '#iD-logo-reset');
76348 reset.append('div').html(_t.html('restore.reset'));
76349 restore.node().focus();
76353 function uiScale(context) {
76354 var projection = context.projection,
76355 isImperial = !_mainLocalizer.usesMetric(),
76359 function scaleDefs(loc1, loc2) {
76360 var lat = (loc2[1] + loc1[1]) / 2,
76361 conversion = isImperial ? 3.28084 : 1,
76362 dist = geoLonToMeters(loc2[0] - loc1[0], lat) * conversion,
76374 buckets = [5280000, 528000, 52800, 5280, 500, 50, 5, 1];
76376 buckets = [5000000, 500000, 50000, 5000, 500, 50, 5, 1];
76377 } // determine a user-friendly endpoint for the scale
76380 for (i = 0; i < buckets.length; i++) {
76384 scale.dist = Math.floor(dist / val) * val;
76387 scale.dist = +dist.toFixed(2);
76391 dLon = geoMetersToLon(scale.dist / conversion, lat);
76392 scale.px = Math.round(projection([loc1[0] + dLon, loc1[1]])[0]);
76393 scale.text = displayLength(scale.dist / conversion, isImperial);
76397 function update(selection) {
76398 // choose loc1, loc2 along bottom of viewport (near where the scale will be drawn)
76399 var dims = context.map().dimensions(),
76400 loc1 = projection.invert([0, dims[1]]),
76401 loc2 = projection.invert([maxLength, dims[1]]),
76402 scale = scaleDefs(loc1, loc2);
76403 selection.select('.scale-path').attr('d', 'M0.5,0.5v' + tickHeight + 'h' + scale.px + 'v-' + tickHeight);
76404 selection.select('.scale-text').style(_mainLocalizer.textDirection() === 'ltr' ? 'left' : 'right', scale.px + 16 + 'px').html(scale.text);
76407 return function (selection) {
76408 function switchUnits() {
76409 isImperial = !isImperial;
76410 selection.call(update);
76413 var scalegroup = selection.append('svg').attr('class', 'scale').on('click', switchUnits).append('g').attr('transform', 'translate(10,11)');
76414 scalegroup.append('path').attr('class', 'scale-path');
76415 selection.append('div').attr('class', 'scale-text');
76416 selection.call(update);
76417 context.map().on('move.scale', function () {
76423 function uiShortcuts(context) {
76424 var detected = utilDetect();
76425 var _activeTab = 0;
76427 var _modalSelection;
76429 var _selection = select(null);
76431 var _dataShortcuts;
76433 function shortcutsModal(_modalSelection) {
76434 _modalSelection.select('.modal').classed('modal-shortcuts', true);
76436 var content = _modalSelection.select('.content');
76438 content.append('div').attr('class', 'modal-section').append('h3').html(_t.html('shortcuts.title'));
76439 _mainFileFetcher.get('shortcuts').then(function (data) {
76440 _dataShortcuts = data;
76441 content.call(render);
76442 })["catch"](function () {
76447 function render(selection) {
76448 if (!_dataShortcuts) return;
76449 var wrapper = selection.selectAll('.wrapper').data([0]);
76450 var wrapperEnter = wrapper.enter().append('div').attr('class', 'wrapper modal-section');
76451 var tabsBar = wrapperEnter.append('div').attr('class', 'tabs-bar');
76452 var shortcutsList = wrapperEnter.append('div').attr('class', 'shortcuts-list');
76453 wrapper = wrapper.merge(wrapperEnter);
76454 var tabs = tabsBar.selectAll('.tab').data(_dataShortcuts);
76455 var tabsEnter = tabs.enter().append('a').attr('class', 'tab').attr('href', '#').on('click', function (d3_event, d) {
76456 d3_event.preventDefault();
76458 var i = _dataShortcuts.indexOf(d);
76463 tabsEnter.append('span').html(function (d) {
76464 return _t.html(d.text);
76467 wrapper.selectAll('.tab').classed('active', function (d, i) {
76468 return i === _activeTab;
76470 var shortcuts = shortcutsList.selectAll('.shortcut-tab').data(_dataShortcuts);
76471 var shortcutsEnter = shortcuts.enter().append('div').attr('class', function (d) {
76472 return 'shortcut-tab shortcut-tab-' + d.tab;
76474 var columnsEnter = shortcutsEnter.selectAll('.shortcut-column').data(function (d) {
76476 }).enter().append('table').attr('class', 'shortcut-column');
76477 var rowsEnter = columnsEnter.selectAll('.shortcut-row').data(function (d) {
76479 }).enter().append('tr').attr('class', 'shortcut-row');
76480 var sectionRows = rowsEnter.filter(function (d) {
76481 return !d.shortcuts;
76483 sectionRows.append('td');
76484 sectionRows.append('td').attr('class', 'shortcut-section').append('h3').html(function (d) {
76485 return _t.html(d.text);
76487 var shortcutRows = rowsEnter.filter(function (d) {
76488 return d.shortcuts;
76490 var shortcutKeys = shortcutRows.append('td').attr('class', 'shortcut-keys');
76491 var modifierKeys = shortcutKeys.filter(function (d) {
76492 return d.modifiers;
76494 modifierKeys.selectAll('kbd.modifier').data(function (d) {
76495 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
76497 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
76500 return d.modifiers;
76502 }).enter().each(function () {
76503 var selection = select(this);
76504 selection.append('kbd').attr('class', 'modifier').html(function (d) {
76505 return uiCmd.display(d);
76507 selection.append('span').html('+');
76509 shortcutKeys.selectAll('kbd.shortcut').data(function (d) {
76510 var arr = d.shortcuts;
76512 if (detected.os === 'win' && d.text === 'shortcuts.editing.commands.redo') {
76514 } else if (detected.os !== 'mac' && d.text === 'shortcuts.browsing.display_options.fullscreen') {
76516 } // replace translations
76519 arr = arr.map(function (s) {
76520 return uiCmd.display(s.indexOf('.') !== -1 ? _t(s) : s);
76522 return utilArrayUniq(arr).map(function (s) {
76525 separator: d.separator,
76529 }).enter().each(function (d, i, nodes) {
76530 var selection = select(this);
76531 var click = d.shortcut.toLowerCase().match(/(.*).click/);
76533 if (click && click[1]) {
76534 // replace "left_click", "right_click" with mouse icon
76535 selection.call(svgIcon('#iD-walkthrough-mouse-' + click[1], 'operation'));
76536 } else if (d.shortcut.toLowerCase() === 'long-press') {
76537 selection.call(svgIcon('#iD-walkthrough-longpress', 'longpress operation'));
76538 } else if (d.shortcut.toLowerCase() === 'tap') {
76539 selection.call(svgIcon('#iD-walkthrough-tap', 'tap operation'));
76541 selection.append('kbd').attr('class', 'shortcut').html(function (d) {
76546 if (i < nodes.length - 1) {
76547 selection.append('span').html(d.separator || "\xA0" + _t.html('shortcuts.or') + "\xA0");
76548 } else if (i === nodes.length - 1 && d.suffix) {
76549 selection.append('span').html(d.suffix);
76552 shortcutKeys.filter(function (d) {
76554 }).each(function () {
76555 var selection = select(this);
76556 selection.append('span').html('+');
76557 selection.append('span').attr('class', 'gesture').html(function (d) {
76558 return _t.html(d.gesture);
76561 shortcutRows.append('td').attr('class', 'shortcut-desc').html(function (d) {
76562 return d.text ? _t.html(d.text) : "\xA0";
76565 wrapper.selectAll('.shortcut-tab').style('display', function (d, i) {
76566 return i === _activeTab ? 'flex' : 'none';
76570 return function (selection, show) {
76571 _selection = selection;
76574 _modalSelection = uiModal(selection);
76576 _modalSelection.call(shortcutsModal);
76578 context.keybinding().on([_t('shortcuts.toggle.key'), '?'], function () {
76579 if (context.container().selectAll('.modal-shortcuts').size()) {
76581 if (_modalSelection) {
76582 _modalSelection.close();
76584 _modalSelection = null;
76587 _modalSelection = uiModal(_selection);
76589 _modalSelection.call(shortcutsModal);
76596 function uiDataHeader() {
76599 function dataHeader(selection) {
76600 var header = selection.selectAll('.data-header').data(_datum ? [_datum] : [], function (d) {
76601 return d.__featurehash__;
76603 header.exit().remove();
76604 var headerEnter = header.enter().append('div').attr('class', 'data-header');
76605 var iconEnter = headerEnter.append('div').attr('class', 'data-header-icon');
76606 iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-data', 'note-fill'));
76607 headerEnter.append('div').attr('class', 'data-header-label').html(_t.html('map_data.layers.custom.title'));
76610 dataHeader.datum = function (val) {
76611 if (!arguments.length) return _datum;
76619 // It is keyed on the `value` of the entry. Data should be an array of objects like:
76621 // value: 'string value', // required
76622 // display: 'label html' // optional
76623 // title: 'hover text' // optional
76624 // terms: ['search terms'] // optional
76627 var _comboHideTimerID;
76629 function uiCombobox(context, klass) {
76630 var dispatch = dispatch$8('accept', 'cancel');
76631 var container = context.container();
76632 var _suggestions = [];
76635 var _selected = null;
76636 var _canAutocomplete = true;
76637 var _caseSensitive = false;
76638 var _cancelFetch = false;
76642 var _mouseEnterHandler, _mouseLeaveHandler;
76644 var _fetcher = function _fetcher(val, cb) {
76645 cb(_data.filter(function (d) {
76646 var terms = d.terms || [];
76647 terms.push(d.value);
76648 return terms.some(function (term) {
76649 return term.toString().toLowerCase().indexOf(val.toLowerCase()) !== -1;
76654 var combobox = function combobox(input, attachTo) {
76655 if (!input || input.empty()) return;
76656 input.classed('combobox-input', true).on('focus.combo-input', focus).on('blur.combo-input', blur).on('keydown.combo-input', keydown).on('keyup.combo-input', keyup).on('input.combo-input', change).on('mousedown.combo-input', mousedown).each(function () {
76657 var parent = this.parentNode;
76658 var sibling = this.nextSibling;
76659 select(parent).selectAll('.combobox-caret').filter(function (d) {
76660 return d === input.node();
76661 }).data([input.node()]).enter().insert('div', function () {
76663 }).attr('class', 'combobox-caret').on('mousedown.combo-caret', function (d3_event) {
76664 d3_event.preventDefault(); // don't steal focus from input
76666 input.node().focus(); // focus the input as if it was clicked
76668 mousedown(d3_event);
76669 }).on('mouseup.combo-caret', function (d3_event) {
76670 d3_event.preventDefault(); // don't steal focus from input
76676 function mousedown(d3_event) {
76677 if (d3_event.button !== 0) return; // left click only
76679 _tDown = +new Date(); // clear selection
76681 var start = input.property('selectionStart');
76682 var end = input.property('selectionEnd');
76684 if (start !== end) {
76685 var val = utilGetSetValue(input);
76686 input.node().setSelectionRange(val.length, val.length);
76690 input.on('mouseup.combo-input', mouseup);
76693 function mouseup(d3_event) {
76694 input.on('mouseup.combo-input', null);
76695 if (d3_event.button !== 0) return; // left click only
76697 if (input.node() !== document.activeElement) return; // exit if this input is not focused
76699 var start = input.property('selectionStart');
76700 var end = input.property('selectionEnd');
76701 if (start !== end) return; // exit if user is selecting
76702 // not showing or showing for a different field - try to show it.
76704 var combo = container.selectAll('.combobox');
76706 if (combo.empty() || combo.datum() !== input.node()) {
76707 var tOrig = _tDown;
76708 window.setTimeout(function () {
76709 if (tOrig !== _tDown) return; // exit if user double clicked
76711 fetchComboData('', function () {
76722 fetchComboData(''); // prefetch values (may warm taginfo cache)
76726 _comboHideTimerID = window.setTimeout(hide, 75);
76730 hide(); // remove any existing
76732 container.insert('div', ':first-child').datum(input.node()).attr('class', 'combobox' + (klass ? ' combobox-' + klass : '')).style('position', 'absolute').style('display', 'block').style('left', '0px').on('mousedown.combo-container', function (d3_event) {
76733 // prevent moving focus out of the input field
76734 d3_event.preventDefault();
76736 container.on('scroll.combo-scroll', render, true);
76740 if (_comboHideTimerID) {
76741 window.clearTimeout(_comboHideTimerID);
76742 _comboHideTimerID = undefined;
76745 container.selectAll('.combobox').remove();
76746 container.on('scroll.combo-scroll', null);
76749 function keydown(d3_event) {
76750 var shown = !container.selectAll('.combobox').empty();
76751 var tagName = input.node() ? input.node().tagName.toLowerCase() : '';
76753 switch (d3_event.keyCode) {
76754 case 8: // ⌫ Backspace
76758 d3_event.stopPropagation();
76761 input.on('input.combo-input', function () {
76762 var start = input.property('selectionStart');
76763 input.node().setSelectionRange(start, start);
76764 input.on('input.combo-input', change);
76775 d3_event.preventDefault();
76776 d3_event.stopPropagation();
76781 if (tagName === 'textarea' && !shown) return;
76782 d3_event.preventDefault();
76784 if (tagName === 'input' && !shown) {
76793 if (tagName === 'textarea' && !shown) return;
76794 d3_event.preventDefault();
76796 if (tagName === 'input' && !shown) {
76805 function keyup(d3_event) {
76806 switch (d3_event.keyCode) {
76817 } // Called whenever the input value is changed (e.g. on typing)
76820 function change() {
76821 fetchComboData(value(), function () {
76823 var val = input.property('value');
76825 if (_suggestions.length) {
76826 if (input.property('selectionEnd') === val.length) {
76827 _selected = tryAutocomplete();
76836 var combo = container.selectAll('.combobox');
76838 if (combo.empty()) {
76847 } // Called when the user presses up/down arrows to navigate the list
76850 function nav(dir) {
76851 if (_suggestions.length) {
76852 // try to determine previously selected index..
76855 for (var i = 0; i < _suggestions.length; i++) {
76856 if (_selected && _suggestions[i].value === _selected) {
76860 } // pick new _selected
76863 index = Math.max(Math.min(index + dir, _suggestions.length - 1), 0);
76864 _selected = _suggestions[index].value;
76865 input.property('value', _selected);
76872 function ensureVisible() {
76873 var combo = container.selectAll('.combobox');
76874 if (combo.empty()) return;
76875 var containerRect = container.node().getBoundingClientRect();
76876 var comboRect = combo.node().getBoundingClientRect();
76878 if (comboRect.bottom > containerRect.bottom) {
76879 var node = attachTo ? attachTo.node() : input.node();
76880 node.scrollIntoView({
76881 behavior: 'instant',
76885 } // https://stackoverflow.com/questions/11039885/scrollintoview-causing-the-whole-page-to-move
76888 var selected = combo.selectAll('.combobox-option.selected').node();
76891 selected.scrollIntoView({
76892 behavior: 'smooth',
76899 var value = input.property('value');
76900 var start = input.property('selectionStart');
76901 var end = input.property('selectionEnd');
76903 if (start && end) {
76904 value = value.substring(0, start);
76910 function fetchComboData(v, cb) {
76911 _cancelFetch = false;
76913 _fetcher.call(input, v, function (results) {
76914 // already chose a value, don't overwrite or autocomplete it
76915 if (_cancelFetch) return;
76916 _suggestions = results;
76917 results.forEach(function (d) {
76918 _fetched[d.value] = d;
76927 function tryAutocomplete() {
76928 if (!_canAutocomplete) return;
76929 var val = _caseSensitive ? value() : value().toLowerCase();
76930 if (!val) return; // Don't autocomplete if user is typing a number - #4935
76932 if (!isNaN(parseFloat(val)) && isFinite(val)) return;
76933 var bestIndex = -1;
76935 for (var i = 0; i < _suggestions.length; i++) {
76936 var suggestion = _suggestions[i].value;
76937 var compare = _caseSensitive ? suggestion : suggestion.toLowerCase(); // if search string matches suggestion exactly, pick it..
76939 if (compare === val) {
76941 break; // otherwise lock in the first result that starts with the search string..
76942 } else if (bestIndex === -1 && compare.indexOf(val) === 0) {
76947 if (bestIndex !== -1) {
76948 var bestVal = _suggestions[bestIndex].value;
76949 input.property('value', bestVal);
76950 input.node().setSelectionRange(val.length, bestVal.length);
76955 function render() {
76956 if (_suggestions.length < _minItems || document.activeElement !== input.node()) {
76961 var shown = !container.selectAll('.combobox').empty();
76962 if (!shown) return;
76963 var combo = container.selectAll('.combobox');
76964 var options = combo.selectAll('.combobox-option').data(_suggestions, function (d) {
76967 options.exit().remove(); // enter/update
76969 options.enter().append('a').attr('class', function (d) {
76970 return 'combobox-option ' + (d.klass || '');
76971 }).attr('title', function (d) {
76973 }).html(function (d) {
76974 return d.display || d.value;
76975 }).on('mouseenter', _mouseEnterHandler).on('mouseleave', _mouseLeaveHandler).merge(options).classed('selected', function (d) {
76976 return d.value === _selected;
76977 }).on('click.combo-option', accept).order();
76978 var node = attachTo ? attachTo.node() : input.node();
76979 var containerRect = container.node().getBoundingClientRect();
76980 var rect = node.getBoundingClientRect();
76981 combo.style('left', rect.left + 5 - containerRect.left + 'px').style('width', rect.width - 10 + 'px').style('top', rect.height + rect.top - containerRect.top + 'px');
76982 } // Dispatches an 'accept' event
76983 // Then hides the combobox.
76986 function accept(d3_event, d) {
76987 _cancelFetch = true;
76988 var thiz = input.node();
76991 // user clicked on a suggestion
76992 utilGetSetValue(input, d.value); // replace field contents
76994 utilTriggerEvent(input, 'change');
76995 } // clear (and keep) selection
76998 var val = utilGetSetValue(input);
76999 thiz.setSelectionRange(val.length, val.length);
77001 dispatch.call('accept', thiz, d, val);
77003 } // Dispatches an 'cancel' event
77004 // Then hides the combobox.
77007 function cancel() {
77008 _cancelFetch = true;
77009 var thiz = input.node(); // clear (and remove) selection, and replace field contents
77011 var val = utilGetSetValue(input);
77012 var start = input.property('selectionStart');
77013 var end = input.property('selectionEnd');
77014 val = val.slice(0, start) + val.slice(end);
77015 utilGetSetValue(input, val);
77016 thiz.setSelectionRange(val.length, val.length);
77017 dispatch.call('cancel', thiz);
77022 combobox.canAutocomplete = function (val) {
77023 if (!arguments.length) return _canAutocomplete;
77024 _canAutocomplete = val;
77028 combobox.caseSensitive = function (val) {
77029 if (!arguments.length) return _caseSensitive;
77030 _caseSensitive = val;
77034 combobox.data = function (val) {
77035 if (!arguments.length) return _data;
77040 combobox.fetcher = function (val) {
77041 if (!arguments.length) return _fetcher;
77046 combobox.minItems = function (val) {
77047 if (!arguments.length) return _minItems;
77052 combobox.itemsMouseEnter = function (val) {
77053 if (!arguments.length) return _mouseEnterHandler;
77054 _mouseEnterHandler = val;
77058 combobox.itemsMouseLeave = function (val) {
77059 if (!arguments.length) return _mouseLeaveHandler;
77060 _mouseLeaveHandler = val;
77064 return utilRebind(combobox, dispatch, 'on');
77067 uiCombobox.off = function (input, context) {
77068 input.on('focus.combo-input', null).on('blur.combo-input', null).on('keydown.combo-input', null).on('keyup.combo-input', null).on('input.combo-input', null).on('mousedown.combo-input', null).on('mouseup.combo-input', null);
77069 context.container().on('scroll.combo-scroll', null);
77072 function uiDisclosure(context, key, expandedDefault) {
77073 var dispatch = dispatch$8('toggled');
77077 var _label = utilFunctor('');
77079 var _updatePreference = true;
77081 var _content = function _content() {};
77083 var disclosure = function disclosure(selection) {
77084 if (_expanded === undefined || _expanded === null) {
77085 // loading _expanded here allows it to be reset by calling `disclosure.expanded(null)`
77086 var preference = corePreferences('disclosure.' + key + '.expanded');
77087 _expanded = preference === null ? !!expandedDefault : preference === 'true';
77090 var hideToggle = selection.selectAll('.hide-toggle-' + key).data([0]); // enter
77092 var hideToggleEnter = hideToggle.enter().append('a').attr('href', '#').attr('class', 'hide-toggle hide-toggle-' + key).call(svgIcon('', 'pre-text', 'hide-toggle-icon'));
77093 hideToggleEnter.append('span').attr('class', 'hide-toggle-text'); // update
77095 hideToggle = hideToggleEnter.merge(hideToggle);
77096 hideToggle.on('click', toggle).classed('expanded', _expanded);
77097 hideToggle.selectAll('.hide-toggle-text').html(_label());
77098 hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
77099 var wrap = selection.selectAll('.disclosure-wrap').data([0]); // enter/update
77101 wrap = wrap.enter().append('div').attr('class', 'disclosure-wrap disclosure-wrap-' + key).merge(wrap).classed('hide', !_expanded);
77104 wrap.call(_content);
77107 function toggle(d3_event) {
77108 d3_event.preventDefault();
77109 _expanded = !_expanded;
77111 if (_updatePreference) {
77112 corePreferences('disclosure.' + key + '.expanded', _expanded);
77115 hideToggle.classed('expanded', _expanded);
77116 hideToggle.selectAll('.hide-toggle-icon').attr('xlink:href', _expanded ? '#iD-icon-down' : _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward');
77117 wrap.call(uiToggle(_expanded));
77120 wrap.call(_content);
77123 dispatch.call('toggled', this, _expanded);
77127 disclosure.label = function (val) {
77128 if (!arguments.length) return _label;
77129 _label = utilFunctor(val);
77133 disclosure.expanded = function (val) {
77134 if (!arguments.length) return _expanded;
77139 disclosure.updatePreference = function (val) {
77140 if (!arguments.length) return _updatePreference;
77141 _updatePreference = val;
77145 disclosure.content = function (val) {
77146 if (!arguments.length) return _content;
77151 return utilRebind(disclosure, dispatch, 'on');
77154 // Can be labeled and collapsible.
77156 function uiSection(id, context) {
77157 var _classes = utilFunctor('');
77159 var _shouldDisplay;
77167 var _expandedByDefault = utilFunctor(true);
77169 var _disclosureContent;
77171 var _disclosureExpanded;
77173 var _containerSelection = select(null);
77179 section.classes = function (val) {
77180 if (!arguments.length) return _classes;
77181 _classes = utilFunctor(val);
77185 section.label = function (val) {
77186 if (!arguments.length) return _label;
77187 _label = utilFunctor(val);
77191 section.expandedByDefault = function (val) {
77192 if (!arguments.length) return _expandedByDefault;
77193 _expandedByDefault = utilFunctor(val);
77197 section.shouldDisplay = function (val) {
77198 if (!arguments.length) return _shouldDisplay;
77199 _shouldDisplay = utilFunctor(val);
77203 section.content = function (val) {
77204 if (!arguments.length) return _content;
77209 section.disclosureContent = function (val) {
77210 if (!arguments.length) return _disclosureContent;
77211 _disclosureContent = val;
77215 section.disclosureExpanded = function (val) {
77216 if (!arguments.length) return _disclosureExpanded;
77217 _disclosureExpanded = val;
77219 }; // may be called multiple times
77222 section.render = function (selection) {
77223 _containerSelection = selection.selectAll('.section-' + id).data([0]);
77225 var sectionEnter = _containerSelection.enter().append('div').attr('class', 'section section-' + id + ' ' + (_classes && _classes() || ''));
77227 _containerSelection = sectionEnter.merge(_containerSelection);
77229 _containerSelection.call(renderContent);
77232 section.reRender = function () {
77233 _containerSelection.call(renderContent);
77236 section.selection = function () {
77237 return _containerSelection;
77240 section.disclosure = function () {
77241 return _disclosure;
77242 }; // may be called multiple times
77245 function renderContent(selection) {
77246 if (_shouldDisplay) {
77247 var shouldDisplay = _shouldDisplay();
77249 selection.classed('hide', !shouldDisplay);
77251 if (!shouldDisplay) {
77252 selection.html('');
77257 if (_disclosureContent) {
77258 if (!_disclosure) {
77259 _disclosure = uiDisclosure(context, id.replace(/-/g, '_'), _expandedByDefault()).label(_label || '')
77260 /*.on('toggled', function(expanded) {
77261 if (expanded) { selection.node().parentNode.scrollTop += 200; }
77263 .content(_disclosureContent);
77266 if (_disclosureExpanded !== undefined) {
77267 _disclosure.expanded(_disclosureExpanded);
77269 _disclosureExpanded = undefined;
77272 selection.call(_disclosure);
77277 selection.call(_content);
77285 // key: 'string', // required
77286 // value: 'string' // optional
77290 // qid: 'string' // brand wikidata (e.g. 'Q37158')
77294 function uiTagReference(what) {
77295 var wikibase = what.qid ? services.wikidata : services.osmWikibase;
77296 var tagReference = {};
77298 var _button = select(null);
77300 var _body = select(null);
77307 if (!wikibase) return;
77309 _button.classed('tag-reference-loading', true);
77311 wikibase.getDocs(what, gotDocs);
77314 function gotDocs(err, docs) {
77317 if (!docs || !docs.title) {
77318 _body.append('p').attr('class', 'tag-reference-description').html(_t.html('inspector.no_documentation_key'));
77324 if (docs.imageURL) {
77325 _body.append('img').attr('class', 'tag-reference-wiki-image').attr('src', docs.imageURL).on('load', function () {
77327 }).on('error', function () {
77328 select(this).remove();
77335 _body.append('p').attr('class', 'tag-reference-description').html(docs.description ? _mainLocalizer.htmlForLocalizedText(docs.description, docs.descriptionLocaleCode) : _t.html('inspector.no_documentation_key')).append('a').attr('class', 'tag-reference-edit').attr('target', '_blank').attr('title', _t('inspector.edit_reference')).attr('href', docs.editURL).call(svgIcon('#iD-icon-edit', 'inline'));
77338 _body.append('a').attr('class', 'tag-reference-link').attr('target', '_blank').attr('href', docs.wiki.url).call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html(docs.wiki.text));
77339 } // Add link to info about "good changeset comments" - #2923
77342 if (what.key === 'comment') {
77343 _body.append('a').attr('class', 'tag-reference-comment-link').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).attr('href', _t('commit.about_changeset_comments_link')).append('span').html(_t.html('commit.about_changeset_comments'));
77350 _button.classed('tag-reference-loading', false);
77352 _body.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1');
77356 _button.selectAll('svg.icon use').each(function () {
77357 var iconUse = select(this);
77359 if (iconUse.attr('href') === '#iD-icon-info') {
77360 iconUse.attr('href', '#iD-icon-info-filled');
77366 _body.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
77367 _body.classed('expanded', false);
77372 _button.selectAll('svg.icon use').each(function () {
77373 var iconUse = select(this);
77375 if (iconUse.attr('href') === '#iD-icon-info-filled') {
77376 iconUse.attr('href', '#iD-icon-info');
77381 tagReference.button = function (selection, klass, iconName) {
77382 _button = selection.selectAll('.tag-reference-button').data([0]);
77383 _button = _button.enter().append('button').attr('class', 'tag-reference-button ' + (klass || '')).attr('title', _t('icons.information')).call(svgIcon('#iD-icon-' + (iconName || 'inspect'))).merge(_button);
77385 _button.on('click', function (d3_event) {
77386 d3_event.stopPropagation();
77387 d3_event.preventDefault();
77388 this.blur(); // avoid keeping focus on the button - #4641
77392 } else if (_loaded) {
77400 tagReference.body = function (selection) {
77401 var itemID = what.qid || what.key + '-' + (what.value || '');
77402 _body = selection.selectAll('.tag-reference-body').data([itemID], function (d) {
77406 _body.exit().remove();
77408 _body = _body.enter().append('div').attr('class', 'tag-reference-body').style('max-height', '0').style('opacity', '0').merge(_body);
77410 if (_showing === false) {
77415 tagReference.showing = function (val) {
77416 if (!arguments.length) return _showing;
77418 return tagReference;
77421 return tagReference;
77424 function uiSectionRawTagEditor(id, context) {
77425 var section = uiSection(id, context).classes('raw-tag-editor').label(function () {
77426 var count = Object.keys(_tags).filter(function (d) {
77429 return _t('inspector.title_count', {
77430 title: _t.html('inspector.tags'),
77433 }).expandedByDefault(false).disclosureContent(renderDisclosureContent);
77434 var taginfo = services.taginfo;
77435 var dispatch = dispatch$8('change');
77436 var availableViews = [{
77438 icon: '#fas-th-list'
77441 icon: '#fas-i-cursor'
77444 var _tagView = corePreferences('raw-tag-editor-view') || 'list'; // 'list, 'text'
77447 var _readOnlyTags = []; // the keys in the order we want them to display
77449 var _orderedKeys = [];
77450 var _showBlank = false;
77451 var _pendingChange = null;
77461 var _didInteract = false;
77463 function interacted() {
77464 _didInteract = true;
77467 function renderDisclosureContent(wrap) {
77468 // remove deleted keys
77469 _orderedKeys = _orderedKeys.filter(function (key) {
77470 return _tags[key] !== undefined;
77471 }); // When switching to a different entity or changing the state (hover/select)
77472 // reorder the keys alphabetically.
77473 // We trigger this by emptying the `_orderedKeys` array, then it will be rebuilt here.
77474 // Otherwise leave their order alone - #5857, #5927
77476 var all = Object.keys(_tags).sort();
77477 var missingKeys = utilArrayDifference(all, _orderedKeys);
77479 for (var i in missingKeys) {
77480 _orderedKeys.push(missingKeys[i]);
77481 } // assemble row data
77484 var rowData = _orderedKeys.map(function (key, i) {
77490 }); // append blank row last, if necessary
77493 if (!rowData.length || _showBlank) {
77494 _showBlank = false;
77496 index: rowData.length,
77503 var options = wrap.selectAll('.raw-tag-options').data([0]);
77504 options.exit().remove();
77505 var optionsEnter = options.enter().insert('div', ':first-child').attr('class', 'raw-tag-options');
77506 var optionEnter = optionsEnter.selectAll('.raw-tag-option').data(availableViews, function (d) {
77509 optionEnter.append('button').attr('class', function (d) {
77510 return 'raw-tag-option raw-tag-option-' + d.id + (_tagView === d.id ? ' selected' : '');
77511 }).attr('title', function (d) {
77512 return _t('icons.' + d.id);
77513 }).on('click', function (d3_event, d) {
77515 corePreferences('raw-tag-editor-view', d.id);
77516 wrap.selectAll('.raw-tag-option').classed('selected', function (datum) {
77517 return datum === d;
77519 wrap.selectAll('.tag-text').classed('hide', d.id !== 'text').each(setTextareaHeight);
77520 wrap.selectAll('.tag-list, .add-row').classed('hide', d.id !== 'list');
77521 }).each(function (d) {
77522 select(this).call(svgIcon(d.icon));
77523 }); // View as Text
77525 var textData = rowsToText(rowData);
77526 var textarea = wrap.selectAll('.tag-text').data([0]);
77527 textarea = textarea.enter().append('textarea').attr('class', 'tag-text' + (_tagView !== 'text' ? ' hide' : '')).call(utilNoAuto).attr('placeholder', _t('inspector.key_value')).attr('spellcheck', 'false').merge(textarea);
77528 textarea.call(utilGetSetValue, textData).each(setTextareaHeight).on('input', setTextareaHeight).on('focus', interacted).on('blur', textChanged).on('change', textChanged); // View as List
77530 var list = wrap.selectAll('.tag-list').data([0]);
77531 list = list.enter().append('ul').attr('class', 'tag-list' + (_tagView !== 'list' ? ' hide' : '')).merge(list); // Container for the Add button
77533 var addRowEnter = wrap.selectAll('.add-row').data([0]).enter().append('div').attr('class', 'add-row' + (_tagView !== 'list' ? ' hide' : ''));
77534 addRowEnter.append('button').attr('class', 'add-tag').call(svgIcon('#iD-icon-plus', 'light')).on('click', addTag);
77535 addRowEnter.append('div').attr('class', 'space-value'); // preserve space
77537 addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
77540 var items = list.selectAll('.tag-row').data(rowData, function (d) {
77543 items.exit().each(unbind).remove(); // Enter
77545 var itemsEnter = items.enter().append('li').attr('class', 'tag-row').classed('readonly', isReadOnly);
77546 var innerWrap = itemsEnter.append('div').attr('class', 'inner-wrap');
77547 innerWrap.append('div').attr('class', 'key-wrap').append('input').property('type', 'text').attr('class', 'key').call(utilNoAuto).on('focus', interacted).on('blur', keyChange).on('change', keyChange);
77548 innerWrap.append('div').attr('class', 'value-wrap').append('input').property('type', 'text').attr('class', 'value').call(utilNoAuto).on('focus', interacted).on('blur', valueChange).on('change', valueChange).on('keydown.push-more', pushMore);
77549 innerWrap.append('button').attr('class', 'form-field-button remove').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete')); // Update
77551 items = items.merge(itemsEnter).sort(function (a, b) {
77552 return a.index - b.index;
77554 items.each(function (d) {
77555 var row = select(this);
77556 var key = row.select('input.key'); // propagate bound data
77558 var value = row.select('input.value'); // propagate bound data
77560 if (_entityIDs && taginfo && _state !== 'hover') {
77561 bindTypeahead(key, value);
77564 var referenceOptions = {
77568 if (typeof d.value === 'string') {
77569 referenceOptions.value = d.value;
77572 var reference = uiTagReference(referenceOptions);
77574 if (_state === 'hover') {
77575 reference.showing(false);
77578 row.select('.inner-wrap') // propagate bound data
77579 .call(reference.button);
77580 row.call(reference.body);
77581 row.select('button.remove'); // propagate bound data
77583 items.selectAll('input.key').attr('title', function (d) {
77585 }).call(utilGetSetValue, function (d) {
77587 }).attr('readonly', function (d) {
77588 return isReadOnly(d) || typeof d.value !== 'string' || null;
77590 items.selectAll('input.value').attr('title', function (d) {
77591 return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : d.value;
77592 }).classed('mixed', function (d) {
77593 return Array.isArray(d.value);
77594 }).attr('placeholder', function (d) {
77595 return typeof d.value === 'string' ? null : _t('inspector.multiple_values');
77596 }).call(utilGetSetValue, function (d) {
77597 return typeof d.value === 'string' ? d.value : '';
77598 }).attr('readonly', function (d) {
77599 return isReadOnly(d) || null;
77601 items.selectAll('button.remove').on(('PointerEvent' in window ? 'pointer' : 'mouse') + 'down', removeTag); // 'click' fires too late - #5878
77604 function isReadOnly(d) {
77605 for (var i = 0; i < _readOnlyTags.length; i++) {
77606 if (d.key.match(_readOnlyTags[i]) !== null) {
77614 function setTextareaHeight() {
77615 if (_tagView !== 'text') return;
77616 var selection = select(this);
77617 var matches = selection.node().value.match(/\n/g);
77618 var lineCount = 2 + Number(matches && matches.length);
77619 var lineHeight = 20;
77620 selection.style('height', lineCount * lineHeight + 'px');
77623 function stringify(s) {
77624 return JSON.stringify(s).slice(1, -1); // without leading/trailing "
77627 function unstringify(s) {
77631 if (s.length < 1 || s.charAt(0) !== '"') {
77635 if (s.length < 2 || s.charAt(s.length - 1) !== '"' || s.charAt(s.length - 1) === '"' && s.charAt(s.length - 2) === '\\') {
77639 return JSON.parse(leading + s + trailing);
77642 function rowsToText(rows) {
77643 var str = rows.filter(function (row) {
77644 return row.key && row.key.trim() !== '';
77645 }).map(function (row) {
77646 var rawVal = row.value;
77647 if (typeof rawVal !== 'string') rawVal = '*';
77648 var val = rawVal ? stringify(rawVal) : '';
77649 return stringify(row.key) + '=' + val;
77652 if (_state !== 'hover' && str.length) {
77659 function textChanged() {
77660 var newText = this.value.trim();
77662 newText.split('\n').forEach(function (row) {
77663 var m = row.match(/^\s*([^=]+)=(.*)$/);
77666 var k = context.cleanTagKey(unstringify(m[1].trim()));
77667 var v = context.cleanTagValue(unstringify(m[2].trim()));
77671 var tagDiff = utilTagDiff(_tags, newTags);
77672 if (!tagDiff.length) return;
77673 _pendingChange = _pendingChange || {};
77674 tagDiff.forEach(function (change) {
77677 })) return; // skip unchanged multiselection placeholders
77679 if (change.newVal === '*' && typeof change.oldVal !== 'string') return;
77681 if (change.type === '-') {
77682 _pendingChange[change.key] = undefined;
77683 } else if (change.type === '+') {
77684 _pendingChange[change.key] = change.newVal || '';
77688 if (Object.keys(_pendingChange).length === 0) {
77689 _pendingChange = null;
77696 function pushMore(d3_event) {
77697 // if pressing Tab on the last value field with content, add a blank row
77698 if (d3_event.keyCode === 9 && !d3_event.shiftKey && section.selection().selectAll('.tag-list li:last-child input.value').node() === this && utilGetSetValue(select(this))) {
77703 function bindTypeahead(key, value) {
77704 if (isReadOnly(key.datum())) return;
77706 if (Array.isArray(value.datum().value)) {
77707 value.call(uiCombobox(context, 'tag-value').minItems(1).fetcher(function (value, callback) {
77708 var keyString = utilGetSetValue(key);
77709 if (!_tags[keyString]) return;
77711 var data = _tags[keyString].filter(Boolean).map(function (tagValue) {
77723 var geometry = context.graph().geometry(_entityIDs[0]);
77724 key.call(uiCombobox(context, 'tag-key').fetcher(function (value, callback) {
77727 geometry: geometry,
77729 }, function (err, data) {
77731 var filtered = data.filter(function (d) {
77732 return _tags[d.value] === undefined;
77734 callback(sort(value, filtered));
77738 value.call(uiCombobox(context, 'tag-value').fetcher(function (value, callback) {
77741 key: utilGetSetValue(key),
77742 geometry: geometry,
77744 }, function (err, data) {
77745 if (!err) callback(sort(value, data));
77749 function sort(value, data) {
77750 var sameletter = [];
77753 for (var i = 0; i < data.length; i++) {
77754 if (data[i].value.substring(0, value.length) === value) {
77755 sameletter.push(data[i]);
77757 other.push(data[i]);
77761 return sameletter.concat(other);
77765 function unbind() {
77766 var row = select(this);
77767 row.selectAll('input.key').call(uiCombobox.off, context);
77768 row.selectAll('input.value').call(uiCombobox.off, context);
77771 function keyChange(d3_event, d) {
77772 if (select(this).attr('readonly')) return;
77773 var kOld = d.key; // exit if we are currently about to delete this row anyway - #6366
77775 if (_pendingChange && _pendingChange.hasOwnProperty(kOld) && _pendingChange[kOld] === undefined) return;
77776 var kNew = context.cleanTagKey(this.value.trim()); // allow no change if the key should be readonly
77785 if (kNew && kNew !== kOld && _tags[kNew] !== undefined) {
77786 // new key is already in use, switch focus to the existing row
77787 this.value = kOld; // reset the key
77789 section.selection().selectAll('.tag-list input.value').each(function (d) {
77790 if (d.key === kNew) {
77791 // send focus to that other value combo instead
77792 var input = select(this).node();
77800 var row = this.parentNode.parentNode;
77801 var inputVal = select(row).selectAll('input.value');
77802 var vNew = context.cleanTagValue(utilGetSetValue(inputVal));
77803 _pendingChange = _pendingChange || {};
77806 _pendingChange[kOld] = undefined;
77809 _pendingChange[kNew] = vNew; // update the ordered key index so this row doesn't change position
77811 var existingKeyIndex = _orderedKeys.indexOf(kOld);
77813 if (existingKeyIndex !== -1) _orderedKeys[existingKeyIndex] = kNew;
77814 d.key = kNew; // update datum to avoid exit/enter on tag update
77818 utilGetSetValue(inputVal, vNew);
77822 function valueChange(d3_event, d) {
77823 if (isReadOnly(d)) return; // exit if this is a multiselection and no value was entered
77825 if (typeof d.value !== 'string' && !this.value) return; // exit if we are currently about to delete this row anyway - #6366
77827 if (_pendingChange && _pendingChange.hasOwnProperty(d.key) && _pendingChange[d.key] === undefined) return;
77828 _pendingChange = _pendingChange || {};
77829 _pendingChange[d.key] = context.cleanTagValue(this.value);
77833 function removeTag(d3_event, d) {
77834 if (isReadOnly(d)) return;
77836 if (d.key === '') {
77837 // removing the blank row
77838 _showBlank = false;
77839 section.reRender();
77841 // remove the key from the ordered key index
77842 _orderedKeys = _orderedKeys.filter(function (key) {
77843 return key !== d.key;
77845 _pendingChange = _pendingChange || {};
77846 _pendingChange[d.key] = undefined;
77851 function addTag() {
77852 // Delay render in case this click is blurring an edited combo.
77853 // Without the setTimeout, the `content` render would wipe out the pending tag change.
77854 window.setTimeout(function () {
77856 section.reRender();
77857 section.selection().selectAll('.tag-list li:last-child input.key').node().focus();
77861 function scheduleChange() {
77862 // Cache IDs in case the editor is reloaded before the change event is called. - #6028
77863 var entityIDs = _entityIDs; // Delay change in case this change is blurring an edited combo. - #5878
77865 window.setTimeout(function () {
77866 if (!_pendingChange) return;
77867 dispatch.call('change', this, entityIDs, _pendingChange);
77868 _pendingChange = null;
77872 section.state = function (val) {
77873 if (!arguments.length) return _state;
77875 if (_state !== val) {
77883 section.presets = function (val) {
77884 if (!arguments.length) return _presets;
77887 if (_presets && _presets.length && _presets[0].isFallback()) {
77888 section.disclosureExpanded(true); // don't collapse the disclosure if the mapper used the raw tag editor - #1881
77889 } else if (!_didInteract) {
77890 section.disclosureExpanded(null);
77896 section.tags = function (val) {
77897 if (!arguments.length) return _tags;
77902 section.entityIDs = function (val) {
77903 if (!arguments.length) return _entityIDs;
77905 if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
77911 }; // pass an array of regular expressions to test against the tag key
77914 section.readOnlyTags = function (val) {
77915 if (!arguments.length) return _readOnlyTags;
77916 _readOnlyTags = val;
77920 return utilRebind(section, dispatch, 'on');
77923 function uiDataEditor(context) {
77924 var dataHeader = uiDataHeader();
77925 var rawTagEditor = uiSectionRawTagEditor('custom-data-tag-editor', context).expandedByDefault(true).readOnlyTags([/./]);
77929 function dataEditor(selection) {
77930 var header = selection.selectAll('.header').data([0]);
77931 var headerEnter = header.enter().append('div').attr('class', 'header fillL');
77932 headerEnter.append('button').attr('class', 'close').on('click', function () {
77933 context.enter(modeBrowse(context));
77934 }).call(svgIcon('#iD-icon-close'));
77935 headerEnter.append('h3').html(_t.html('map_data.title'));
77936 var body = selection.selectAll('.body').data([0]);
77937 body = body.enter().append('div').attr('class', 'body').merge(body);
77938 var editor = body.selectAll('.data-editor').data([0]); // enter/update
77940 editor.enter().append('div').attr('class', 'modal-section data-editor').merge(editor).call(dataHeader.datum(_datum));
77941 var rte = body.selectAll('.raw-tag-editor').data([0]); // enter/update
77943 rte.enter().append('div').attr('class', 'raw-tag-editor data-editor').merge(rte).call(rawTagEditor.tags(_datum && _datum.properties || {}).state('hover').render).selectAll('textarea.tag-text').attr('readonly', true).classed('readonly', true);
77946 dataEditor.datum = function (val) {
77947 if (!arguments.length) return _datum;
77955 var sexagesimal = {exports: {}};
77957 sexagesimal.exports = element;
77958 var pair_1 = sexagesimal.exports.pair = pair;
77959 sexagesimal.exports.format = format;
77960 sexagesimal.exports.formatPair = formatPair;
77961 sexagesimal.exports.coordToDMS = coordToDMS;
77963 function element(input, dims) {
77964 var result = search(input, dims);
77965 return result === null ? null : result.val;
77968 function formatPair(input) {
77969 return format(input.lat, 'lat') + ' ' + format(input.lon, 'lon');
77970 } // Is 0 North or South?
77973 function format(input, dim) {
77974 var dms = coordToDMS(input, dim);
77975 return dms.whole + '° ' + (dms.minutes ? dms.minutes + '\' ' : '') + (dms.seconds ? dms.seconds + '" ' : '') + dms.dir;
77978 function coordToDMS(input, dim) {
77983 var dir = dirs[input >= 0 ? 0 : 1];
77984 var abs = Math.abs(input);
77985 var whole = Math.floor(abs);
77986 var fraction = abs - whole;
77987 var fractionMinutes = fraction * 60;
77988 var minutes = Math.floor(fractionMinutes);
77989 var seconds = Math.floor((fractionMinutes - minutes) * 60);
77998 function search(input, dims) {
77999 if (!dims) dims = 'NSEW';
78000 if (typeof input !== 'string') return null;
78001 input = input.toUpperCase();
78002 var regex = /^[\s\,]*([NSEW])?\s*([\-|\—|\―]?[0-9.]+)[°º˚]?\s*(?:([0-9.]+)['’′‘]\s*)?(?:([0-9.]+)(?:''|"|”|″)\s*)?([NSEW])?/;
78003 var m = input.match(regex);
78004 if (!m) return null; // no match
78006 var matched = m[0]; // extract dimension.. m[1] = leading, m[5] = trailing
78010 if (m[1] && m[5]) {
78011 // if matched both..
78012 dim = m[1]; // keep leading
78014 matched = matched.slice(0, -1); // remove trailing dimension from match
78016 dim = m[1] || m[5];
78017 } // if unrecognized dimension
78020 if (dim && dims.indexOf(dim) === -1) return null; // extract DMS
78022 var deg = m[2] ? parseFloat(m[2]) : 0;
78023 var min = m[3] ? parseFloat(m[3]) / 60 : 0;
78024 var sec = m[4] ? parseFloat(m[4]) / 3600 : 0;
78025 var sign = deg < 0 ? -1 : 1;
78026 if (dim === 'S' || dim === 'W') sign *= -1;
78028 val: (Math.abs(deg) + min + sec) * sign,
78031 remain: input.slice(matched.length)
78035 function pair(input, dims) {
78036 input = input.trim();
78037 var one = search(input, dims);
78038 if (!one) return null;
78039 input = one.remain.trim();
78040 var two = search(input, dims);
78041 if (!two || two.remain) return null;
78044 return swapdim(one.val, two.val, one.dim);
78046 return [one.val, two.val];
78050 function swapdim(a, b, dim) {
78051 if (dim === 'N' || dim === 'S') return [a, b];
78052 if (dim === 'W' || dim === 'E') return [b, a];
78055 function uiFeatureList(context) {
78056 var _geocodeResults;
78058 function featureList(selection) {
78059 var header = selection.append('div').attr('class', 'header fillL');
78060 header.append('h3').html(_t.html('inspector.feature_list'));
78061 var searchWrap = selection.append('div').attr('class', 'search-header');
78062 searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
78063 var search = searchWrap.append('input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keypress', keypress).on('keydown', keydown).on('input', inputevent);
78064 var listWrap = selection.append('div').attr('class', 'inspector-body');
78065 var list = listWrap.append('div').attr('class', 'feature-list');
78066 context.on('exit.feature-list', clearSearch);
78067 context.map().on('drawn.feature-list', mapDrawn);
78068 context.keybinding().on(uiCmd('⌘F'), focusSearch);
78070 function focusSearch(d3_event) {
78071 var mode = context.mode() && context.mode().id;
78072 if (mode !== 'browse') return;
78073 d3_event.preventDefault();
78074 search.node().focus();
78077 function keydown(d3_event) {
78078 if (d3_event.keyCode === 27) {
78080 search.node().blur();
78084 function keypress(d3_event) {
78085 var q = search.property('value'),
78086 items = list.selectAll('.feature-list-item');
78088 if (d3_event.keyCode === 13 && // ↩ Return
78089 q.length && items.size()) {
78090 click(d3_event, items.datum());
78094 function inputevent() {
78095 _geocodeResults = undefined;
78099 function clearSearch() {
78100 search.property('value', '');
78104 function mapDrawn(e) {
78110 function features() {
78112 var graph = context.graph();
78113 var visibleCenter = context.map().extent().center();
78114 var q = search.property('value').toLowerCase();
78115 if (!q) return result;
78116 var locationMatch = pair_1(q.toUpperCase()) || q.match(/^(-?\d+\.?\d*)\s+(-?\d+\.?\d*)$/);
78118 if (locationMatch) {
78119 var loc = [parseFloat(locationMatch[0]), parseFloat(locationMatch[1])];
78123 type: _t('inspector.location'),
78124 name: dmsCoordinatePair([loc[1], loc[0]]),
78127 } // A location search takes priority over an ID search
78130 var idMatch = !locationMatch && q.match(/(?:^|\W)(node|way|relation|[nwr])\W?0*([1-9]\d*)(?:\W|$)/i);
78133 var elemType = idMatch[1].charAt(0);
78134 var elemId = idMatch[2];
78136 id: elemType + elemId,
78137 geometry: elemType === 'n' ? 'point' : elemType === 'w' ? 'line' : 'relation',
78138 type: elemType === 'n' ? _t('inspector.node') : elemType === 'w' ? _t('inspector.way') : _t('inspector.relation'),
78143 var allEntities = graph.entities;
78144 var localResults = [];
78146 for (var id in allEntities) {
78147 var entity = allEntities[id];
78148 if (!entity) continue;
78149 var name = utilDisplayName(entity) || '';
78150 if (name.toLowerCase().indexOf(q) < 0) continue;
78151 var matched = _mainPresetIndex.match(entity, graph);
78152 var type = matched && matched.name() || utilDisplayType(entity.id);
78153 var extent = entity.extent(graph);
78154 var distance = extent ? geoSphericalDistance(visibleCenter, extent.center()) : 0;
78155 localResults.push({
78158 geometry: entity.geometry(graph),
78163 if (localResults.length > 100) break;
78166 localResults = localResults.sort(function byDistance(a, b) {
78167 return a.distance - b.distance;
78169 result = result.concat(localResults);
78171 (_geocodeResults || []).forEach(function (d) {
78172 if (d.osm_type && d.osm_id) {
78173 // some results may be missing these - #1890
78174 // Make a temporary osmEntity so we can preset match
78175 // and better localize the search result - #4725
78176 var id = osmEntity.id.fromOSM(d.osm_type, d.osm_id);
78178 tags[d["class"]] = d.type;
78185 if (d.osm_type === 'way') {
78186 // for ways, add some fake closed nodes
78187 attrs.nodes = ['a', 'a']; // so that geometry area is possible
78190 var tempEntity = osmEntity(attrs);
78191 var tempGraph = coreGraph([tempEntity]);
78192 var matched = _mainPresetIndex.match(tempEntity, tempGraph);
78193 var type = matched && matched.name() || utilDisplayType(id);
78196 geometry: tempEntity.geometry(tempGraph),
78198 name: d.display_name,
78199 extent: new geoExtent([parseFloat(d.boundingbox[3]), parseFloat(d.boundingbox[0])], [parseFloat(d.boundingbox[2]), parseFloat(d.boundingbox[1])])
78204 if (q.match(/^[0-9]+$/)) {
78205 // if query is just a number, possibly an OSM ID without a prefix
78209 type: _t('inspector.node'),
78215 type: _t('inspector.way'),
78220 geometry: 'relation',
78221 type: _t('inspector.relation'),
78229 function drawList() {
78230 var value = search.property('value');
78231 var results = features();
78232 list.classed('filtered', value.length);
78233 var resultsIndicator = list.selectAll('.no-results-item').data([0]).enter().append('button').property('disabled', true).attr('class', 'no-results-item').call(svgIcon('#iD-icon-alert', 'pre-text'));
78234 resultsIndicator.append('span').attr('class', 'entity-name');
78235 list.selectAll('.no-results-item .entity-name').html(_t.html('geocoder.no_results_worldwide'));
78237 if (services.geocoder) {
78238 list.selectAll('.geocode-item').data([0]).enter().append('button').attr('class', 'geocode-item secondary-action').on('click', geocoderSearch).append('div').attr('class', 'label').append('span').attr('class', 'entity-name').html(_t.html('geocoder.search'));
78241 list.selectAll('.no-results-item').style('display', value.length && !results.length ? 'block' : 'none');
78242 list.selectAll('.geocode-item').style('display', value && _geocodeResults === undefined ? 'block' : 'none');
78243 list.selectAll('.feature-list-item').data([-1]).remove();
78244 var items = list.selectAll('.feature-list-item').data(results, function (d) {
78247 var enter = items.enter().insert('button', '.geocode-item').attr('class', 'feature-list-item').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
78248 var label = enter.append('div').attr('class', 'label');
78249 label.each(function (d) {
78250 select(this).call(svgIcon('#iD-icon-' + d.geometry, 'pre-text'));
78252 label.append('span').attr('class', 'entity-type').html(function (d) {
78255 label.append('span').attr('class', 'entity-name').html(function (d) {
78258 enter.style('opacity', 0).transition().style('opacity', 1);
78260 items.exit().remove();
78263 function mouseover(d3_event, d) {
78264 if (d.id === -1) return;
78265 utilHighlightEntities([d.id], true, context);
78268 function mouseout(d3_event, d) {
78269 if (d.id === -1) return;
78270 utilHighlightEntities([d.id], false, context);
78273 function click(d3_event, d) {
78274 d3_event.preventDefault();
78277 context.map().centerZoomEase([d.location[1], d.location[0]], 19);
78278 } else if (d.entity) {
78279 utilHighlightEntities([d.id], false, context);
78280 context.enter(modeSelect(context, [d.entity.id]));
78281 context.map().zoomToEase(d.entity);
78283 // download, zoom to, and select the entity with the given ID
78284 context.zoomToEntity(d.id);
78288 function geocoderSearch() {
78289 services.geocoder.search(search.property('value'), function (err, resp) {
78290 _geocodeResults = resp || [];
78296 return featureList;
78300 var getOwnPropertyDescriptor$1 = objectGetOwnPropertyDescriptor.f;
78301 var toLength$1 = toLength$q;
78302 var notARegExp$1 = notARegexp;
78303 var requireObjectCoercible$1 = requireObjectCoercible$e;
78304 var correctIsRegExpLogic$1 = correctIsRegexpLogic;
78306 // eslint-disable-next-line es/no-string-prototype-startswith -- safe
78307 var $startsWith = ''.startsWith;
78308 var min$1 = Math.min;
78310 var CORRECT_IS_REGEXP_LOGIC$1 = correctIsRegExpLogic$1('startsWith');
78311 // https://github.com/zloirock/core-js/pull/702
78312 var MDN_POLYFILL_BUG$1 = !CORRECT_IS_REGEXP_LOGIC$1 && !!function () {
78313 var descriptor = getOwnPropertyDescriptor$1(String.prototype, 'startsWith');
78314 return descriptor && !descriptor.writable;
78317 // `String.prototype.startsWith` method
78318 // https://tc39.es/ecma262/#sec-string.prototype.startswith
78319 $$1({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG$1 && !CORRECT_IS_REGEXP_LOGIC$1 }, {
78320 startsWith: function startsWith(searchString /* , position = 0 */) {
78321 var that = String(requireObjectCoercible$1(this));
78322 notARegExp$1(searchString);
78323 var index = toLength$1(min$1(arguments.length > 1 ? arguments[1] : undefined, that.length));
78324 var search = String(searchString);
78326 ? $startsWith.call(that, search, index)
78327 : that.slice(index, index + search.length) === search;
78331 function uiSectionEntityIssues(context) {
78332 // Does the user prefer to expand the active issue? Useful for viewing tag diff.
78333 // Expand by default so first timers see it - #6408, #8143
78334 var preference = corePreferences('entity-issues.reference.expanded');
78336 var _expanded = preference === null ? true : preference === 'true';
78338 var _entityIDs = [];
78341 var _activeIssueID;
78343 var section = uiSection('entity-issues', context).shouldDisplay(function () {
78344 return _issues.length > 0;
78345 }).label(function () {
78346 return _t('inspector.title_count', {
78347 title: _t.html('issues.list_title'),
78348 count: _issues.length
78350 }).disclosureContent(renderDisclosureContent);
78351 context.validator().on('validated.entity_issues', function () {
78352 // Refresh on validated events
78354 section.reRender();
78355 }).on('focusedIssue.entity_issues', function (issue) {
78356 makeActiveIssue(issue.id);
78359 function reloadIssues() {
78360 _issues = context.validator().getSharedEntityIssues(_entityIDs, {
78361 includeDisabledRules: true
78365 function makeActiveIssue(issueID) {
78366 _activeIssueID = issueID;
78367 section.selection().selectAll('.issue-container').classed('active', function (d) {
78368 return d.id === _activeIssueID;
78372 function renderDisclosureContent(selection) {
78373 selection.classed('grouped-items-area', true);
78374 _activeIssueID = _issues.length > 0 ? _issues[0].id : null;
78375 var containers = selection.selectAll('.issue-container').data(_issues, function (d) {
78379 containers.exit().remove(); // Enter
78381 var containersEnter = containers.enter().append('div').attr('class', 'issue-container');
78382 var itemsEnter = containersEnter.append('div').attr('class', function (d) {
78383 return 'issue severity-' + d.severity;
78384 }).on('mouseover.highlight', function (d3_event, d) {
78385 // don't hover-highlight the selected entity
78386 var ids = d.entityIds.filter(function (e) {
78387 return _entityIDs.indexOf(e) === -1;
78389 utilHighlightEntities(ids, true, context);
78390 }).on('mouseout.highlight', function (d3_event, d) {
78391 var ids = d.entityIds.filter(function (e) {
78392 return _entityIDs.indexOf(e) === -1;
78394 utilHighlightEntities(ids, false, context);
78396 var labelsEnter = itemsEnter.append('div').attr('class', 'issue-label');
78397 var textEnter = labelsEnter.append('button').attr('class', 'issue-text').on('click', function (d3_event, d) {
78398 makeActiveIssue(d.id); // expand only the clicked item
78400 var extent = d.extent(context.graph());
78403 var setZoom = Math.max(context.map().zoom(), 19);
78404 context.map().unobscuredCenterZoomEase(extent.center(), setZoom);
78407 textEnter.each(function (d) {
78408 var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
78409 select(this).call(svgIcon(iconName, 'issue-icon'));
78411 textEnter.append('span').attr('class', 'issue-message');
78412 var infoButton = labelsEnter.append('button').attr('class', 'issue-info-button').attr('title', _t('icons.information')).call(svgIcon('#iD-icon-inspect'));
78413 infoButton.on('click', function (d3_event) {
78414 d3_event.stopPropagation();
78415 d3_event.preventDefault();
78416 this.blur(); // avoid keeping focus on the button - #4641
78418 var container = select(this.parentNode.parentNode.parentNode);
78419 var info = container.selectAll('.issue-info');
78420 var isExpanded = info.classed('expanded');
78421 _expanded = !isExpanded;
78422 corePreferences('entity-issues.reference.expanded', _expanded); // update preference
78425 info.transition().duration(200).style('max-height', '0px').style('opacity', '0').on('end', function () {
78426 info.classed('expanded', false);
78429 info.classed('expanded', true).transition().duration(200).style('max-height', '200px').style('opacity', '1').on('end', function () {
78430 info.style('max-height', null);
78434 itemsEnter.append('ul').attr('class', 'issue-fix-list');
78435 containersEnter.append('div').attr('class', 'issue-info' + (_expanded ? ' expanded' : '')).style('max-height', _expanded ? null : '0').style('opacity', _expanded ? '1' : '0').each(function (d) {
78436 if (typeof d.reference === 'function') {
78437 select(this).call(d.reference);
78439 select(this).html(_t.html('inspector.no_documentation_key'));
78443 containers = containers.merge(containersEnter).classed('active', function (d) {
78444 return d.id === _activeIssueID;
78446 containers.selectAll('.issue-message').html(function (d) {
78447 return d.message(context);
78450 var fixLists = containers.selectAll('.issue-fix-list');
78451 var fixes = fixLists.selectAll('.issue-fix-item').data(function (d) {
78452 return d.fixes ? d.fixes(context) : [];
78453 }, function (fix) {
78456 fixes.exit().remove();
78457 var fixesEnter = fixes.enter().append('li').attr('class', 'issue-fix-item');
78458 var buttons = fixesEnter.append('button').on('click', function (d3_event, d) {
78459 // not all fixes are actionable
78460 if (select(this).attr('disabled') || !d.onClick) return; // Don't run another fix for this issue within a second of running one
78461 // (Necessary for "Select a feature type" fix. Most fixes should only ever run once)
78463 if (d.issue.dateLastRanFix && new Date() - d.issue.dateLastRanFix < 1000) return;
78464 d.issue.dateLastRanFix = new Date(); // remove hover-highlighting
78466 utilHighlightEntities(d.issue.entityIds.concat(d.entityIds), false, context);
78467 new Promise(function (resolve, reject) {
78468 d.onClick(context, resolve, reject);
78470 if (d.onClick.length <= 1) {
78471 // if the fix doesn't take any completion parameters then consider it resolved
78474 }).then(function () {
78475 // revalidate whenever the fix has finished running successfully
78476 context.validator().validate();
78478 }).on('mouseover.highlight', function (d3_event, d) {
78479 utilHighlightEntities(d.entityIds, true, context);
78480 }).on('mouseout.highlight', function (d3_event, d) {
78481 utilHighlightEntities(d.entityIds, false, context);
78483 buttons.each(function (d) {
78484 var iconName = d.icon || 'iD-icon-wrench';
78486 if (iconName.startsWith('maki')) {
78490 select(this).call(svgIcon('#' + iconName, 'fix-icon'));
78492 buttons.append('span').attr('class', 'fix-message').html(function (d) {
78495 fixesEnter.merge(fixes).selectAll('button').classed('actionable', function (d) {
78497 }).attr('disabled', function (d) {
78498 return d.onClick ? null : 'true';
78499 }).attr('title', function (d) {
78500 if (d.disabledReason) {
78501 return d.disabledReason;
78508 section.entityIDs = function (val) {
78509 if (!arguments.length) return _entityIDs;
78511 if (!_entityIDs || !val || !utilArrayIdentical(_entityIDs, val)) {
78513 _activeIssueID = null;
78523 function uiPresetIcon() {
78528 var _sizeClass = 'medium';
78530 function isSmall() {
78531 return _sizeClass === 'small';
78534 function presetIcon(selection) {
78535 selection.each(render);
78538 function getIcon(p, geom) {
78539 if (isSmall() && p.isFallback && p.isFallback()) return 'iD-icon-' + p.id;
78540 if (p.icon) return p.icon;
78541 if (geom === 'line') return 'iD-other-line';
78542 if (geom === 'vertex') return p.isFallback() ? '' : 'temaki-vertex';
78543 if (isSmall() && geom === 'point') return '';
78544 return 'maki-marker-stroked';
78547 function renderPointBorder(container, drawPoint) {
78548 var pointBorder = container.selectAll('.preset-icon-point-border').data(drawPoint ? [0] : []);
78549 pointBorder.exit().remove();
78550 var pointBorderEnter = pointBorder.enter();
78553 pointBorderEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-point-border').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h)).append('path').attr('transform', 'translate(11.5, 8)').attr('d', 'M 17,8 C 17,13 11,21 8.5,23.5 C 6,21 0,13 0,8 C 0,4 4,-0.5 8.5,-0.5 C 13,-0.5 17,4 17,8 z');
78554 pointBorder = pointBorderEnter.merge(pointBorder);
78557 function renderCategoryBorder(container, category) {
78558 var categoryBorder = container.selectAll('.preset-icon-category-border').data(category ? [0] : []);
78559 categoryBorder.exit().remove();
78560 var categoryBorderEnter = categoryBorder.enter();
78562 var svgEnter = categoryBorderEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-category-border').attr('width', d).attr('height', d).attr('viewBox', "0 0 ".concat(d, " ").concat(d));
78563 ['fill', 'stroke'].forEach(function (klass) {
78564 svgEnter.append('path').attr('class', "area ".concat(klass)).attr('d', 'M9.5,7.5 L25.5,7.5 L28.5,12.5 L49.5,12.5 C51.709139,12.5 53.5,14.290861 53.5,16.5 L53.5,43.5 C53.5,45.709139 51.709139,47.5 49.5,47.5 L10.5,47.5 C8.290861,47.5 6.5,45.709139 6.5,43.5 L6.5,12.5 L9.5,7.5 Z');
78566 categoryBorder = categoryBorderEnter.merge(categoryBorder);
78569 var tagClasses = svgTagClasses().getClassesString(category.members.collection[0].addTags, '');
78570 categoryBorder.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
78571 categoryBorder.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
78575 function renderCircleFill(container, drawVertex) {
78576 var vertexFill = container.selectAll('.preset-icon-fill-vertex').data(drawVertex ? [0] : []);
78577 vertexFill.exit().remove();
78578 var vertexFillEnter = vertexFill.enter();
78582 vertexFillEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-fill-vertex').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h)).append('circle').attr('cx', w / 2).attr('cy', h / 2).attr('r', d / 2);
78583 vertexFill = vertexFillEnter.merge(vertexFill);
78586 function renderSquareFill(container, drawArea, tagClasses) {
78587 var fill = container.selectAll('.preset-icon-fill-area').data(drawArea ? [0] : []);
78588 fill.exit().remove();
78589 var fillEnter = fill.enter();
78590 var d = isSmall() ? 40 : 60;
78594 var c1 = (w - l) / 2;
78596 fillEnter = fillEnter.append('svg').attr('class', 'preset-icon-fill preset-icon-fill-area').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
78597 ['fill', 'stroke'].forEach(function (klass) {
78598 fillEnter.append('path').attr('d', "M".concat(c1, " ").concat(c1, " L").concat(c1, " ").concat(c2, " L").concat(c2, " ").concat(c2, " L").concat(c2, " ").concat(c1, " Z")).attr('class', "area ".concat(klass));
78601 [[c1, c1], [c1, c2], [c2, c2], [c2, c1]].forEach(function (point) {
78602 fillEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', rVertex);
78606 var rMidpoint = 1.25;
78607 [[c1, w / 2], [c2, w / 2], [h / 2, c1], [h / 2, c2]].forEach(function (point) {
78608 fillEnter.append('circle').attr('class', 'midpoint').attr('cx', point[0]).attr('cy', point[1]).attr('r', rMidpoint);
78612 fill = fillEnter.merge(fill);
78613 fill.selectAll('path.stroke').attr('class', "area stroke ".concat(tagClasses));
78614 fill.selectAll('path.fill').attr('class', "area fill ".concat(tagClasses));
78617 function renderLine(container, drawLine, tagClasses) {
78618 var line = container.selectAll('.preset-icon-line').data(drawLine ? [0] : []);
78619 line.exit().remove();
78620 var lineEnter = line.enter();
78621 var d = isSmall() ? 40 : 60; // draw the line parametrically
78625 var y = Math.round(d * 0.72);
78626 var l = Math.round(d * 0.6);
78628 var x1 = (w - l) / 2;
78630 lineEnter = lineEnter.append('svg').attr('class', 'preset-icon-line').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
78631 ['casing', 'stroke'].forEach(function (klass) {
78632 lineEnter.append('path').attr('d', "M".concat(x1, " ").concat(y, " L").concat(x2, " ").concat(y)).attr('class', "line ".concat(klass));
78634 [[x1 - 1, y], [x2 + 1, y]].forEach(function (point) {
78635 lineEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
78637 line = lineEnter.merge(line);
78638 line.selectAll('path.stroke').attr('class', "line stroke ".concat(tagClasses));
78639 line.selectAll('path.casing').attr('class', "line casing ".concat(tagClasses));
78642 function renderRoute(container, drawRoute, p) {
78643 var route = container.selectAll('.preset-icon-route').data(drawRoute ? [0] : []);
78644 route.exit().remove();
78645 var routeEnter = route.enter();
78646 var d = isSmall() ? 40 : 60; // draw the route parametrically
78650 var y1 = Math.round(d * 0.80);
78651 var y2 = Math.round(d * 0.68);
78652 var l = Math.round(d * 0.6);
78654 var x1 = (w - l) / 2;
78655 var x2 = x1 + l / 3;
78656 var x3 = x2 + l / 3;
78657 var x4 = x3 + l / 3;
78658 routeEnter = routeEnter.append('svg').attr('class', 'preset-icon-route').attr('width', w).attr('height', h).attr('viewBox', "0 0 ".concat(w, " ").concat(h));
78659 ['casing', 'stroke'].forEach(function (klass) {
78660 routeEnter.append('path').attr('d', "M".concat(x1, " ").concat(y1, " L").concat(x2, " ").concat(y2)).attr('class', "segment0 line ".concat(klass));
78661 routeEnter.append('path').attr('d', "M".concat(x2, " ").concat(y2, " L").concat(x3, " ").concat(y1)).attr('class', "segment1 line ".concat(klass));
78662 routeEnter.append('path').attr('d', "M".concat(x3, " ").concat(y1, " L").concat(x4, " ").concat(y2)).attr('class', "segment2 line ".concat(klass));
78664 [[x1, y1], [x2, y2], [x3, y1], [x4, y2]].forEach(function (point) {
78665 routeEnter.append('circle').attr('class', 'vertex').attr('cx', point[0]).attr('cy', point[1]).attr('r', r);
78667 route = routeEnter.merge(route);
78670 var routeType = p.tags.type === 'waterway' ? 'waterway' : p.tags.route;
78671 var segmentPresetIDs = routeSegments[routeType];
78673 for (var i in segmentPresetIDs) {
78674 var segmentPreset = _mainPresetIndex.item(segmentPresetIDs[i]);
78675 var segmentTagClasses = svgTagClasses().getClassesString(segmentPreset.tags, '');
78676 route.selectAll("path.stroke.segment".concat(i)).attr('class', "segment".concat(i, " line stroke ").concat(segmentTagClasses));
78677 route.selectAll("path.casing.segment".concat(i)).attr('class', "segment".concat(i, " line casing ").concat(segmentTagClasses));
78682 function renderSvgIcon(container, picon, geom, isFramed, category, tagClasses) {
78683 var isMaki = picon && /^maki-/.test(picon);
78684 var isTemaki = picon && /^temaki-/.test(picon);
78685 var isFa = picon && /^fa[srb]-/.test(picon);
78686 var isiDIcon = picon && !(isMaki || isTemaki || isFa);
78687 var icon = container.selectAll('.preset-icon').data(picon ? [0] : []);
78688 icon.exit().remove();
78689 icon = icon.enter().append('div').attr('class', 'preset-icon').call(svgIcon('')).merge(icon);
78690 icon.attr('class', 'preset-icon ' + (geom ? geom + '-geom' : '')).classed('category', category).classed('framed', isFramed).classed('preset-icon-iD', isiDIcon);
78691 icon.selectAll('svg').attr('class', 'icon ' + picon + ' ' + (!isiDIcon && geom !== 'line' ? '' : tagClasses));
78695 suffix = isSmall() && geom === 'point' ? '-11' : '-15';
78698 icon.selectAll('use').attr('href', '#' + picon + suffix);
78701 function renderImageIcon(container, imageURL) {
78702 var imageIcon = container.selectAll('img.image-icon').data(imageURL ? [0] : []);
78703 imageIcon.exit().remove();
78704 imageIcon = imageIcon.enter().append('img').attr('class', 'image-icon').on('load', function () {
78705 return container.classed('showing-img', true);
78706 }).on('error', function () {
78707 return container.classed('showing-img', false);
78708 }).merge(imageIcon);
78709 imageIcon.attr('src', imageURL);
78710 } // Route icons are drawn with a zigzag annotation underneath:
78714 // This dataset defines the styles that are used to draw the zigzag segments.
78717 var routeSegments = {
78718 bicycle: ['highway/cycleway', 'highway/cycleway', 'highway/cycleway'],
78719 bus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
78720 trolleybus: ['highway/unclassified', 'highway/secondary', 'highway/primary'],
78721 detour: ['highway/tertiary', 'highway/residential', 'highway/unclassified'],
78722 ferry: ['route/ferry', 'route/ferry', 'route/ferry'],
78723 foot: ['highway/footway', 'highway/footway', 'highway/footway'],
78724 hiking: ['highway/path', 'highway/path', 'highway/path'],
78725 horse: ['highway/bridleway', 'highway/bridleway', 'highway/bridleway'],
78726 light_rail: ['railway/light_rail', 'railway/light_rail', 'railway/light_rail'],
78727 monorail: ['railway/monorail', 'railway/monorail', 'railway/monorail'],
78728 mtb: ['highway/path', 'highway/track', 'highway/bridleway'],
78729 pipeline: ['man_made/pipeline', 'man_made/pipeline', 'man_made/pipeline'],
78730 piste: ['piste/downhill', 'piste/hike', 'piste/nordic'],
78731 power: ['power/line', 'power/line', 'power/line'],
78732 road: ['highway/secondary', 'highway/primary', 'highway/trunk'],
78733 subway: ['railway/subway', 'railway/subway', 'railway/subway'],
78734 train: ['railway/rail', 'railway/rail', 'railway/rail'],
78735 tram: ['railway/tram', 'railway/tram', 'railway/tram'],
78736 waterway: ['waterway/stream', 'waterway/stream', 'waterway/stream']
78739 function render() {
78740 var p = _preset.apply(this, arguments);
78742 var geom = _geometry ? _geometry.apply(this, arguments) : null;
78744 if (geom === 'relation' && p.tags && (p.tags.type === 'route' && p.tags.route && routeSegments[p.tags.route] || p.tags.type === 'waterway')) {
78748 var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
78749 var isFallback = isSmall() && p.isFallback && p.isFallback();
78750 var imageURL = showThirdPartyIcons === 'true' && p.imageURL;
78751 var picon = getIcon(p, geom);
78752 var isCategory = !p.setTags;
78753 var drawPoint = picon && geom === 'point' && isSmall() && !isFallback;
78754 var drawVertex = picon !== null && geom === 'vertex' && (!isSmall() || !isFallback);
78755 var drawLine = picon && geom === 'line' && !isFallback && !isCategory;
78756 var drawArea = picon && geom === 'area' && !isFallback && !isCategory;
78757 var drawRoute = picon && geom === 'route';
78758 var isFramed = drawVertex || drawArea || drawLine || drawRoute || isCategory;
78759 var tags = !isCategory ? p.setTags({}, geom) : {};
78761 for (var k in tags) {
78762 if (tags[k] === '*') {
78767 var tagClasses = svgTagClasses().getClassesString(tags, '');
78768 var selection = select(this);
78769 var container = selection.selectAll('.preset-icon-container').data([0]);
78770 container = container.enter().append('div').attr('class', "preset-icon-container ".concat(_sizeClass)).merge(container);
78771 container.classed('showing-img', !!imageURL).classed('fallback', isFallback);
78772 renderCategoryBorder(container, isCategory && p);
78773 renderPointBorder(container, drawPoint);
78774 renderCircleFill(container, drawVertex);
78775 renderSquareFill(container, drawArea, tagClasses);
78776 renderLine(container, drawLine, tagClasses);
78777 renderRoute(container, drawRoute, p);
78778 renderSvgIcon(container, picon, geom, isFramed, isCategory, tagClasses);
78779 renderImageIcon(container, imageURL);
78782 presetIcon.preset = function (val) {
78783 if (!arguments.length) return _preset;
78784 _preset = utilFunctor(val);
78788 presetIcon.geometry = function (val) {
78789 if (!arguments.length) return _geometry;
78790 _geometry = utilFunctor(val);
78794 presetIcon.sizeClass = function (val) {
78795 if (!arguments.length) return _sizeClass;
78803 function uiSectionFeatureType(context) {
78804 var dispatch = dispatch$8('choose');
78805 var _entityIDs = [];
78810 var section = uiSection('feature-type', context).label(_t.html('inspector.feature_type')).disclosureContent(renderDisclosureContent);
78812 function renderDisclosureContent(selection) {
78813 selection.classed('preset-list-item', true);
78814 selection.classed('mixed-types', _presets.length > 1);
78815 var presetButtonWrap = selection.selectAll('.preset-list-button-wrap').data([0]).enter().append('div').attr('class', 'preset-list-button-wrap');
78816 var presetButton = presetButtonWrap.append('button').attr('class', 'preset-list-button preset-reset').call(uiTooltip().title(_t.html('inspector.back_tooltip')).placement('bottom'));
78817 presetButton.append('div').attr('class', 'preset-icon-container');
78818 presetButton.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
78819 presetButtonWrap.append('div').attr('class', 'accessory-buttons');
78820 var tagReferenceBodyWrap = selection.selectAll('.tag-reference-body-wrap').data([0]);
78821 tagReferenceBodyWrap = tagReferenceBodyWrap.enter().append('div').attr('class', 'tag-reference-body-wrap').merge(tagReferenceBodyWrap); // update header
78823 if (_tagReference) {
78824 selection.selectAll('.preset-list-button-wrap .accessory-buttons').style('display', _presets.length === 1 ? null : 'none').call(_tagReference.button);
78825 tagReferenceBodyWrap.style('display', _presets.length === 1 ? null : 'none').call(_tagReference.body);
78828 selection.selectAll('.preset-reset').on('click', function () {
78829 dispatch.call('choose', this, _presets);
78830 }).on('pointerdown pointerup mousedown mouseup', function (d3_event) {
78831 d3_event.preventDefault();
78832 d3_event.stopPropagation();
78834 var geometries = entityGeometries();
78835 selection.select('.preset-list-item button').call(uiPresetIcon().geometry(_presets.length === 1 ? geometries.length === 1 && geometries[0] : null).preset(_presets.length === 1 ? _presets[0] : _mainPresetIndex.item('point')));
78836 var names = _presets.length === 1 ? [_presets[0].nameLabel(), _presets[0].subtitleLabel()].filter(Boolean) : [_t('inspector.multiple_types')];
78837 var label = selection.select('.label-inner');
78838 var nameparts = label.selectAll('.namepart').data(names, function (d) {
78841 nameparts.exit().remove();
78842 nameparts.enter().append('div').attr('class', 'namepart').html(function (d) {
78847 section.entityIDs = function (val) {
78848 if (!arguments.length) return _entityIDs;
78853 section.presets = function (val) {
78854 if (!arguments.length) return _presets; // don't reload the same preset
78856 if (!utilArrayIdentical(val, _presets)) {
78859 if (_presets.length === 1) {
78860 _tagReference = uiTagReference(_presets[0].reference()).showing(false);
78867 function entityGeometries() {
78870 for (var i in _entityIDs) {
78871 var geometry = context.graph().geometry(_entityIDs[i]);
78872 if (!counts[geometry]) counts[geometry] = 0;
78873 counts[geometry] += 1;
78876 return Object.keys(counts).sort(function (geom1, geom2) {
78877 return counts[geom2] - counts[geom1];
78881 return utilRebind(section, dispatch, 'on');
78884 // It borrows some code from uiHelp
78886 function uiFieldHelp(context, fieldName) {
78887 var fieldHelp = {};
78889 var _inspector = select(null);
78891 var _wrap = select(null);
78893 var _body = select(null);
78895 var fieldHelpKeys = {
78896 restrictions: [['about', ['about', 'from_via_to', 'maxdist', 'maxvia']], ['inspecting', ['about', 'from_shadow', 'allow_shadow', 'restrict_shadow', 'only_shadow', 'restricted', 'only']], ['modifying', ['about', 'indicators', 'allow_turn', 'restrict_turn', 'only_turn']], ['tips', ['simple', 'simple_example', 'indirect', 'indirect_example', 'indirect_noedit']]]
78898 var fieldHelpHeadings = {};
78899 var replacements = {
78900 distField: _t.html('restriction.controls.distance'),
78901 viaField: _t.html('restriction.controls.via'),
78902 fromShadow: icon('#iD-turn-shadow', 'inline shadow from'),
78903 allowShadow: icon('#iD-turn-shadow', 'inline shadow allow'),
78904 restrictShadow: icon('#iD-turn-shadow', 'inline shadow restrict'),
78905 onlyShadow: icon('#iD-turn-shadow', 'inline shadow only'),
78906 allowTurn: icon('#iD-turn-yes', 'inline turn'),
78907 restrictTurn: icon('#iD-turn-no', 'inline turn'),
78908 onlyTurn: icon('#iD-turn-only', 'inline turn')
78909 }; // For each section, squash all the texts into a single markdown document
78911 var docs = fieldHelpKeys[fieldName].map(function (key) {
78912 var helpkey = 'help.field.' + fieldName + '.' + key[0];
78913 var text = key[1].reduce(function (all, part) {
78914 var subkey = helpkey + '.' + part;
78915 var depth = fieldHelpHeadings[subkey]; // is this subkey a heading?
78917 var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
78919 return all + hhh + _t.html(subkey, replacements) + '\n\n';
78923 title: _t.html(helpkey + '.title'),
78924 html: marked_1(text.trim())
78931 _body.classed('hide', false).style('opacity', '0').transition().duration(200).style('opacity', '1');
78935 _body.classed('hide', true).transition().duration(200).style('opacity', '0').on('end', function () {
78936 _body.classed('hide', true);
78940 function clickHelp(index) {
78941 var d = docs[index];
78942 var tkeys = fieldHelpKeys[fieldName][index][1];
78944 _body.selectAll('.field-help-nav-item').classed('active', function (d, i) {
78945 return i === index;
78948 var content = _body.selectAll('.field-help-content').html(d.html); // class the paragraphs so we can find and style them
78951 content.selectAll('p').attr('class', function (d, i) {
78953 }); // insert special content for certain help sections
78955 if (d.key === 'help.field.restrictions.inspecting') {
78956 content.insert('img', 'p.from_shadow').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_inspect.gif'));
78957 } else if (d.key === 'help.field.restrictions.modifying') {
78958 content.insert('img', 'p.allow_turn').attr('class', 'field-help-image cf').attr('src', context.imagePath('tr_modify.gif'));
78962 fieldHelp.button = function (selection) {
78963 if (_body.empty()) return;
78964 var button = selection.selectAll('.field-help-button').data([0]); // enter/update
78966 button.enter().append('button').attr('class', 'field-help-button').call(svgIcon('#iD-icon-help')).merge(button).on('click', function (d3_event) {
78967 d3_event.stopPropagation();
78968 d3_event.preventDefault();
78970 if (_body.classed('hide')) {
78978 function updatePosition() {
78979 var wrap = _wrap.node();
78981 var inspector = _inspector.node();
78983 var wRect = wrap.getBoundingClientRect();
78984 var iRect = inspector.getBoundingClientRect();
78986 _body.style('top', wRect.top + inspector.scrollTop - iRect.top + 'px');
78989 fieldHelp.body = function (selection) {
78990 // This control expects the field to have a form-field-input-wrap div
78991 _wrap = selection.selectAll('.form-field-input-wrap');
78992 if (_wrap.empty()) return; // absolute position relative to the inspector, so it "floats" above the fields
78994 _inspector = context.container().select('.sidebar .entity-editor-pane .inspector-body');
78995 if (_inspector.empty()) return;
78996 _body = _inspector.selectAll('.field-help-body').data([0]);
78998 var enter = _body.enter().append('div').attr('class', 'field-help-body hide'); // initially hidden
79001 var titleEnter = enter.append('div').attr('class', 'field-help-title cf');
79002 titleEnter.append('h2').attr('class', _mainLocalizer.textDirection() === 'rtl' ? 'fr' : 'fl').html(_t.html('help.field.' + fieldName + '.title'));
79003 titleEnter.append('button').attr('class', 'fr close').on('click', function (d3_event) {
79004 d3_event.stopPropagation();
79005 d3_event.preventDefault();
79007 }).call(svgIcon('#iD-icon-close'));
79008 var navEnter = enter.append('div').attr('class', 'field-help-nav cf');
79009 var titles = docs.map(function (d) {
79012 navEnter.selectAll('.field-help-nav-item').data(titles).enter().append('div').attr('class', 'field-help-nav-item').html(function (d) {
79014 }).on('click', function (d3_event, d) {
79015 d3_event.stopPropagation();
79016 d3_event.preventDefault();
79017 clickHelp(titles.indexOf(d));
79019 enter.append('div').attr('class', 'field-help-content');
79020 _body = _body.merge(enter);
79027 function uiFieldCheck(field, context) {
79028 var dispatch = dispatch$8('change');
79029 var options = field.options;
79035 var input = select(null);
79036 var text = select(null);
79037 var label = select(null);
79038 var reverser = select(null);
79042 var _entityIDs = [];
79047 for (var i in options) {
79048 var v = options[i];
79049 values.push(v === 'undefined' ? undefined : v);
79050 texts.push(field.t.html('options.' + v, {
79055 values = [undefined, 'yes'];
79056 texts = [_t.html('inspector.unknown'), _t.html('inspector.check.yes')];
79058 if (field.type !== 'defaultCheck') {
79060 texts.push(_t.html('inspector.check.no'));
79062 } // Checks tags to see whether an undefined value is "Assumed to be Yes"
79065 function checkImpliedYes() {
79066 _impliedYes = field.id === 'oneway_yes'; // hack: pretend `oneway` field is a `oneway_yes` field
79067 // where implied oneway tag exists (e.g. `junction=roundabout`) #2220, #1841
79069 if (field.id === 'oneway') {
79070 var entity = context.entity(_entityIDs[0]);
79072 for (var key in entity.tags) {
79073 if (key in osmOneWayTags && entity.tags[key] in osmOneWayTags[key]) {
79074 _impliedYes = true;
79075 texts[0] = _t.html('_tagging.presets.fields.oneway_yes.options.undefined');
79082 function reverserHidden() {
79083 if (!context.container().select('div.inspector-hover').empty()) return true;
79084 return !(_value === 'yes' || _impliedYes && !_value);
79087 function reverserSetText(selection) {
79088 var entity = _entityIDs.length && context.hasEntity(_entityIDs[0]);
79089 if (reverserHidden() || !entity) return selection;
79090 var first = entity.first();
79091 var last = entity.isClosed() ? entity.nodes[entity.nodes.length - 2] : entity.last();
79092 var pseudoDirection = first < last;
79093 var icon = pseudoDirection ? '#iD-icon-forward' : '#iD-icon-backward';
79094 selection.selectAll('.reverser-span').html(_t.html('inspector.check.reverser')).call(svgIcon(icon, 'inline'));
79098 var check = function check(selection) {
79100 label = selection.selectAll('.form-field-input-wrap').data([0]);
79101 var enter = label.enter().append('label').attr('class', 'form-field-input-wrap form-field-input-check');
79102 enter.append('input').property('indeterminate', field.type !== 'defaultCheck').attr('type', 'checkbox').attr('id', field.domId);
79103 enter.append('span').html(texts[0]).attr('class', 'value');
79105 if (field.type === 'onewayCheck') {
79106 enter.append('button').attr('class', 'reverser' + (reverserHidden() ? ' hide' : '')).append('span').attr('class', 'reverser-span');
79109 label = label.merge(enter);
79110 input = label.selectAll('input');
79111 text = label.selectAll('span.value');
79112 input.on('click', function (d3_event) {
79113 d3_event.stopPropagation();
79116 if (Array.isArray(_tags[field.key])) {
79117 if (values.indexOf('yes') !== -1) {
79118 t[field.key] = 'yes';
79120 t[field.key] = values[0];
79123 t[field.key] = values[(values.indexOf(_value) + 1) % values.length];
79124 } // Don't cycle through `alternating` or `reversible` states - #4970
79125 // (They are supported as translated strings, but should not toggle with clicks)
79128 if (t[field.key] === 'reversible' || t[field.key] === 'alternating') {
79129 t[field.key] = values[0];
79132 dispatch.call('change', this, t);
79135 if (field.type === 'onewayCheck') {
79136 reverser = label.selectAll('.reverser');
79137 reverser.call(reverserSetText).on('click', function (d3_event) {
79138 d3_event.preventDefault();
79139 d3_event.stopPropagation();
79140 context.perform(function (graph) {
79141 for (var i in _entityIDs) {
79142 graph = actionReverse(_entityIDs[i])(graph);
79146 }, _t('operations.reverse.annotation.line', {
79148 })); // must manually revalidate since no 'change' event was called
79150 context.validator().validate();
79151 select(this).call(reverserSetText);
79156 check.entityIDs = function (val) {
79157 if (!arguments.length) return _entityIDs;
79162 check.tags = function (tags) {
79165 function isChecked(val) {
79166 return val !== 'no' && val !== '' && val !== undefined && val !== null;
79169 function textFor(val) {
79170 if (val === '') val = undefined;
79171 var index = values.indexOf(val);
79172 return index !== -1 ? texts[index] : '"' + val + '"';
79176 var isMixed = Array.isArray(tags[field.key]);
79177 _value = !isMixed && tags[field.key] && tags[field.key].toLowerCase();
79179 if (field.type === 'onewayCheck' && (_value === '1' || _value === '-1')) {
79183 input.property('indeterminate', isMixed || field.type !== 'defaultCheck' && !_value).property('checked', isChecked(_value));
79184 text.html(isMixed ? _t.html('inspector.multiple_values') : textFor(_value)).classed('mixed', isMixed);
79185 label.classed('set', !!_value);
79187 if (field.type === 'onewayCheck') {
79188 reverser.classed('hide', reverserHidden()).call(reverserSetText);
79192 check.focus = function () {
79193 input.node().focus();
79196 return utilRebind(check, dispatch, 'on');
79199 function uiFieldCombo(field, context) {
79200 var dispatch = dispatch$8('change');
79202 var _isMulti = field.type === 'multiCombo' || field.type === 'manyCombo';
79204 var _isNetwork = field.type === 'networkCombo';
79206 var _isSemi = field.type === 'semiCombo';
79208 var _optarray = field.options;
79210 var _showTagInfoSuggestions = field.type !== 'manyCombo' && field.autoSuggestions !== false;
79212 var _allowCustomValues = field.type !== 'manyCombo' && field.customValues !== false;
79214 var _snake_case = field.snake_case || field.snake_case === undefined;
79216 var _combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(field.caseSensitive).minItems(_isMulti || _isSemi ? 1 : 2);
79218 var _container = select(null);
79220 var _inputWrap = select(null);
79222 var _input = select(null);
79224 var _comboData = [];
79225 var _multiData = [];
79226 var _entityIDs = [];
79232 var _staticPlaceholder; // initialize deprecated tags array
79235 var _dataDeprecated = [];
79236 _mainFileFetcher.get('deprecated').then(function (d) {
79237 _dataDeprecated = d;
79238 })["catch"](function () {
79240 }); // ensure multiCombo field.key ends with a ':'
79242 if (_isMulti && field.key && /[^:]$/.test(field.key)) {
79246 function snake(s) {
79247 return s.replace(/\s+/g, '_').toLowerCase();
79250 function clean(s) {
79251 return s.split(';').map(function (s) {
79254 } // returns the tag value for a display value
79255 // (for multiCombo, dval should be the key suffix, not the entire key)
79258 function tagValue(dval) {
79259 dval = clean(dval || '');
79261 var found = _comboData.find(function (o) {
79262 return o.key && clean(o.value) === dval;
79265 if (found) return found.key;
79267 if (field.type === 'typeCombo' && !dval) {
79271 return (_snake_case ? snake(dval) : dval) || undefined;
79272 } // returns the display value for a tag value
79273 // (for multiCombo, tval should be the key suffix, not the entire key)
79276 function displayValue(tval) {
79279 if (field.hasTextForStringId('options.' + tval)) {
79280 return field.t('options.' + tval, {
79285 if (field.type === 'typeCombo' && tval.toLowerCase() === 'yes') {
79290 } // Compute the difference between arrays of objects by `value` property
79292 // objectDifference([{value:1}, {value:2}, {value:3}], [{value:2}])
79293 // > [{value:1}, {value:3}]
79297 function objectDifference(a, b) {
79298 return a.filter(function (d1) {
79299 return !b.some(function (d2) {
79300 return !d2.isMixed && d1.value === d2.value;
79305 function initCombo(selection, attachTo) {
79306 if (!_allowCustomValues) {
79307 selection.attr('readonly', 'readonly');
79310 if (_showTagInfoSuggestions && services.taginfo) {
79311 selection.call(_combobox.fetcher(setTaginfoValues), attachTo);
79312 setTaginfoValues('', setPlaceholder);
79314 selection.call(_combobox, attachTo);
79315 setStaticValues(setPlaceholder);
79319 function setStaticValues(callback) {
79320 if (!_optarray) return;
79321 _comboData = _optarray.map(function (v) {
79324 value: field.t('options.' + v, {
79328 display: field.t.html('options.' + v, {
79331 klass: field.hasTextForStringId('options.' + v) ? '' : 'raw-option'
79335 _combobox.data(objectDifference(_comboData, _multiData));
79337 if (callback) callback(_comboData);
79340 function setTaginfoValues(q, callback) {
79341 var fn = _isMulti ? 'multikeys' : 'values';
79342 var query = (_isMulti ? field.key : '') + q;
79343 var hasCountryPrefix = _isNetwork && _countryCode && _countryCode.indexOf(q.toLowerCase()) === 0;
79345 if (hasCountryPrefix) {
79346 query = _countryCode + ':';
79350 debounce: q !== '',
79355 if (_entityIDs.length) {
79356 params.geometry = context.graph().geometry(_entityIDs[0]);
79359 services.taginfo[fn](params, function (err, data) {
79361 data = data.filter(function (d) {
79362 if (field.type === 'typeCombo' && d.value === 'yes') {
79363 // don't show the fallback value
79365 } // don't show values with very low usage
79368 return !d.count || d.count > 10;
79370 var deprecatedValues = osmEntity.deprecatedTagValuesByKey(_dataDeprecated)[field.key];
79372 if (deprecatedValues) {
79373 // don't suggest deprecated tag values
79374 data = data.filter(function (d) {
79375 return deprecatedValues.indexOf(d.value) === -1;
79379 if (hasCountryPrefix) {
79380 data = data.filter(function (d) {
79381 return d.value.toLowerCase().indexOf(_countryCode + ':') === 0;
79383 } // hide the caret if there are no suggestions
79386 _container.classed('empty-combobox', data.length === 0);
79388 _comboData = data.map(function (d) {
79390 if (_isMulti) k = k.replace(field.key, '');
79391 var label = field.t('options.' + k, {
79397 display: field.t.html('options.' + k, {
79400 title: d.title || label,
79401 klass: field.hasTextForStringId('options.' + k) ? '' : 'raw-option'
79404 _comboData = objectDifference(_comboData, _multiData);
79405 if (callback) callback(_comboData);
79409 function setPlaceholder(values) {
79410 if (_isMulti || _isSemi) {
79411 _staticPlaceholder = field.placeholder() || _t('inspector.add');
79413 var vals = values.map(function (d) {
79415 }).filter(function (s) {
79416 return s.length < 20;
79418 var placeholders = vals.length > 1 ? vals : values.map(function (d) {
79421 _staticPlaceholder = field.placeholder() || placeholders.slice(0, 3).join(', ');
79424 if (!/(…|\.\.\.)$/.test(_staticPlaceholder)) {
79425 _staticPlaceholder += '…';
79430 if (!_isMulti && !_isSemi && _tags && Array.isArray(_tags[field.key])) {
79431 ph = _t('inspector.multiple_values');
79433 ph = _staticPlaceholder;
79436 _container.selectAll('input').attr('placeholder', ph);
79439 function change() {
79443 if (_isMulti || _isSemi) {
79444 val = tagValue(utilGetSetValue(_input).replace(/,/g, ';')) || '';
79446 _container.classed('active', false);
79448 utilGetSetValue(_input, '');
79449 var vals = val.split(';').filter(Boolean);
79450 if (!vals.length) return;
79453 utilArrayUniq(vals).forEach(function (v) {
79454 var key = (field.key || '') + v;
79457 // don't set a multicombo value to 'yes' if it already has a non-'no' value
79458 // e.g. `language:de=main`
79459 var old = _tags[key];
79460 if (typeof old === 'string' && old.toLowerCase() !== 'no') return;
79463 key = context.cleanTagKey(key);
79464 field.keys.push(key);
79467 } else if (_isSemi) {
79468 var arr = _multiData.map(function (d) {
79472 arr = arr.concat(vals);
79473 t[field.key] = context.cleanTagValue(utilArrayUniq(arr).filter(Boolean).join(';'));
79476 window.setTimeout(function () {
79477 _input.node().focus();
79480 var rawValue = utilGetSetValue(_input); // don't override multiple values with blank string
79482 if (!rawValue && Array.isArray(_tags[field.key])) return;
79483 val = context.cleanTagValue(tagValue(rawValue));
79484 t[field.key] = val || undefined;
79487 dispatch.call('change', this, t);
79490 function removeMultikey(d3_event, d) {
79491 d3_event.preventDefault();
79492 d3_event.stopPropagation();
79496 t[d.key] = undefined;
79497 } else if (_isSemi) {
79498 var arr = _multiData.map(function (md) {
79499 return md.key === d.key ? null : md.key;
79500 }).filter(Boolean);
79502 arr = utilArrayUniq(arr);
79503 t[field.key] = arr.length ? arr.join(';') : undefined;
79506 dispatch.call('change', this, t);
79509 function combo(selection) {
79510 _container = selection.selectAll('.form-field-input-wrap').data([0]);
79511 var type = _isMulti || _isSemi ? 'multicombo' : 'combo';
79512 _container = _container.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + type).merge(_container);
79514 if (_isMulti || _isSemi) {
79515 _container = _container.selectAll('.chiplist').data([0]);
79516 var listClass = 'chiplist'; // Use a separate line for each value in the Destinations and Via fields
79517 // to mimic highway exit signs
79519 if (field.key === 'destination' || field.key === 'via') {
79520 listClass += ' full-line-chips';
79523 _container = _container.enter().append('ul').attr('class', listClass).on('click', function () {
79524 window.setTimeout(function () {
79525 _input.node().focus();
79527 }).merge(_container);
79528 _inputWrap = _container.selectAll('.input-wrap').data([0]);
79529 _inputWrap = _inputWrap.enter().append('li').attr('class', 'input-wrap').merge(_inputWrap);
79530 _input = _inputWrap.selectAll('input').data([0]);
79532 _input = _container.selectAll('input').data([0]);
79535 _input = _input.enter().append('input').attr('type', 'text').attr('id', field.domId).call(utilNoAuto).call(initCombo, selection).merge(_input);
79538 var extent = combinedEntityExtent();
79539 var countryCode = extent && iso1A2Code(extent.center());
79540 _countryCode = countryCode && countryCode.toLowerCase();
79543 _input.on('change', change).on('blur', change);
79545 _input.on('keydown.field', function (d3_event) {
79546 switch (d3_event.keyCode) {
79549 _input.node().blur(); // blurring also enters the value
79552 d3_event.stopPropagation();
79557 if (_isMulti || _isSemi) {
79558 _combobox.on('accept', function () {
79559 _input.node().blur();
79561 _input.node().focus();
79564 _input.on('focus', function () {
79565 _container.classed('active', true);
79570 combo.tags = function (tags) {
79573 if (_isMulti || _isSemi) {
79578 // Build _multiData array containing keys already set..
79579 for (var k in tags) {
79580 if (field.key && k.indexOf(field.key) !== 0) continue;
79581 if (!field.key && field.keys.indexOf(k) === -1) continue;
79583 if (!v || typeof v === 'string' && v.toLowerCase() === 'no') continue;
79584 var suffix = field.key ? k.substr(field.key.length) : k;
79588 value: displayValue(suffix),
79589 isMixed: Array.isArray(v)
79594 // Set keys for form-field modified (needed for undo and reset buttons)..
79595 field.keys = _multiData.map(function (d) {
79597 }); // limit the input length so it fits after prepending the key prefix
79599 maxLength = context.maxCharsForTagKey() - utilUnicodeCharsCount(field.key);
79601 maxLength = context.maxCharsForTagKey();
79603 } else if (_isSemi) {
79604 var allValues = [];
79607 if (Array.isArray(tags[field.key])) {
79608 tags[field.key].forEach(function (tagVal) {
79609 var thisVals = utilArrayUniq((tagVal || '').split(';')).filter(Boolean);
79610 allValues = allValues.concat(thisVals);
79612 if (!commonValues) {
79613 commonValues = thisVals;
79615 commonValues = commonValues.filter(function (value) {
79616 return thisVals.includes(value);
79620 allValues = utilArrayUniq(allValues).filter(Boolean);
79622 allValues = utilArrayUniq((tags[field.key] || '').split(';')).filter(Boolean);
79623 commonValues = allValues;
79626 _multiData = allValues.map(function (v) {
79629 value: displayValue(v),
79630 isMixed: !commonValues.includes(v)
79633 var currLength = utilUnicodeCharsCount(commonValues.join(';')); // limit the input length to the remaining available characters
79635 maxLength = context.maxCharsForTagValue() - currLength;
79637 if (currLength > 0) {
79638 // account for the separator if a new value will be appended to existing
79641 } // a negative maxlength doesn't make sense
79644 maxLength = Math.max(0, maxLength);
79645 var allowDragAndDrop = _isSemi // only semiCombo values are ordered
79646 && !Array.isArray(tags[field.key]); // Exclude existing multikeys from combo options..
79648 var available = objectDifference(_comboData, _multiData);
79650 _combobox.data(available); // Hide 'Add' button if this field uses fixed set of
79651 // options and they're all currently used,
79652 // or if the field is already at its character limit
79655 var hideAdd = !_allowCustomValues && !available.length || maxLength <= 0;
79657 _container.selectAll('.chiplist .input-wrap').style('display', hideAdd ? 'none' : null); // Render chips
79660 var chips = _container.selectAll('.chip').data(_multiData);
79662 chips.exit().remove();
79663 var enter = chips.enter().insert('li', '.input-wrap').attr('class', 'chip');
79664 enter.append('span');
79666 chips = chips.merge(enter).order().classed('raw-value', function (d) {
79668 if (_isMulti) k = k.replace(field.key, '');
79669 return !field.hasTextForStringId('options.' + k);
79670 }).classed('draggable', allowDragAndDrop).classed('mixed', function (d) {
79672 }).attr('title', function (d) {
79673 return d.isMixed ? _t('inspector.unshared_value_tooltip') : null;
79676 if (allowDragAndDrop) {
79677 registerDragAndDrop(chips);
79680 chips.select('span').html(function (d) {
79683 chips.select('a').attr('href', '#').on('click', removeMultikey).attr('class', 'remove').html('×');
79685 var isMixed = Array.isArray(tags[field.key]);
79686 var mixedValues = isMixed && tags[field.key].map(function (val) {
79687 return displayValue(val);
79688 }).filter(Boolean);
79689 var showsValue = !isMixed && tags[field.key] && !(field.type === 'typeCombo' && tags[field.key] === 'yes');
79690 var isRawValue = showsValue && !field.hasTextForStringId('options.' + tags[field.key]);
79691 var isKnownValue = showsValue && !isRawValue;
79692 var isReadOnly = !_allowCustomValues || isKnownValue;
79693 utilGetSetValue(_input, !isMixed ? displayValue(tags[field.key]) : '').classed('raw-value', isRawValue).classed('known-value', isKnownValue).attr('readonly', isReadOnly ? 'readonly' : undefined).attr('title', isMixed ? mixedValues.join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : _staticPlaceholder || '').classed('mixed', isMixed).on('keydown.deleteCapture', function (d3_event) {
79694 if (isReadOnly && isKnownValue && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
79695 d3_event.preventDefault();
79696 d3_event.stopPropagation();
79698 t[field.key] = undefined;
79699 dispatch.call('change', this, t);
79705 function registerDragAndDrop(selection) {
79706 // allow drag and drop re-ordering of chips
79707 var dragOrigin, targetIndex;
79708 selection.call(d3_drag().on('start', function (d3_event) {
79713 targetIndex = null;
79714 }).on('drag', function (d3_event) {
79715 var x = d3_event.x - dragOrigin.x,
79716 y = d3_event.y - dragOrigin.y;
79717 if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
79718 Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
79719 var index = selection.nodes().indexOf(this);
79720 select(this).classed('dragging', true);
79721 targetIndex = null;
79722 var targetIndexOffsetTop = null;
79723 var draggedTagWidth = select(this).node().offsetWidth;
79725 if (field.key === 'destination' || field.key === 'via') {
79726 // meaning tags are full width
79727 _container.selectAll('.chip').style('transform', function (d2, index2) {
79728 var node = select(this).node();
79730 if (index === index2) {
79731 return 'translate(' + x + 'px, ' + y + 'px)'; // move the dragged tag up the order
79732 } else if (index2 > index && d3_event.y > node.offsetTop) {
79733 if (targetIndex === null || index2 > targetIndex) {
79734 targetIndex = index2;
79737 return 'translateY(-100%)'; // move the dragged tag down the order
79738 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
79739 if (targetIndex === null || index2 < targetIndex) {
79740 targetIndex = index2;
79743 return 'translateY(100%)';
79749 _container.selectAll('.chip').each(function (d2, index2) {
79750 var node = select(this).node(); // check the cursor is in the bounding box
79752 if (index !== index2 && d3_event.x < node.offsetLeft + node.offsetWidth + 5 && d3_event.x > node.offsetLeft && d3_event.y < node.offsetTop + node.offsetHeight && d3_event.y > node.offsetTop) {
79753 targetIndex = index2;
79754 targetIndexOffsetTop = node.offsetTop;
79756 }).style('transform', function (d2, index2) {
79757 var node = select(this).node();
79759 if (index === index2) {
79760 return 'translate(' + x + 'px, ' + y + 'px)';
79761 } // only translate tags in the same row
79764 if (node.offsetTop === targetIndexOffsetTop) {
79765 if (index2 < index && index2 >= targetIndex) {
79766 return 'translateX(' + draggedTagWidth + 'px)';
79767 } else if (index2 > index && index2 <= targetIndex) {
79768 return 'translateX(-' + draggedTagWidth + 'px)';
79775 }).on('end', function () {
79776 if (!select(this).classed('dragging')) {
79780 var index = selection.nodes().indexOf(this);
79781 select(this).classed('dragging', false);
79783 _container.selectAll('.chip').style('transform', null);
79785 if (typeof targetIndex === 'number') {
79786 var element = _multiData[index];
79788 _multiData.splice(index, 1);
79790 _multiData.splice(targetIndex, 0, element);
79794 if (_multiData.length) {
79795 t[field.key] = _multiData.map(function (element) {
79796 return element.key;
79799 t[field.key] = undefined;
79802 dispatch.call('change', this, t);
79805 dragOrigin = undefined;
79806 targetIndex = undefined;
79810 combo.focus = function () {
79811 _input.node().focus();
79814 combo.entityIDs = function (val) {
79815 if (!arguments.length) return _entityIDs;
79820 function combinedEntityExtent() {
79821 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
79824 return utilRebind(combo, dispatch, 'on');
79827 function uiFieldText(field, context) {
79828 var dispatch = dispatch$8('change');
79829 var input = select(null);
79830 var outlinkButton = select(null);
79831 var _entityIDs = [];
79835 var _phoneFormats = {};
79837 if (field.type === 'tel') {
79838 _mainFileFetcher.get('phone_formats').then(function (d) {
79840 updatePhonePlaceholder();
79841 })["catch"](function () {
79846 function calcLocked() {
79847 // Protect certain fields that have a companion `*:wikidata` value
79848 var isLocked = (field.id === 'brand' || field.id === 'network' || field.id === 'operator' || field.id === 'flag') && _entityIDs.length && _entityIDs.some(function (entityID) {
79849 var entity = context.graph().hasEntity(entityID);
79850 if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
79852 if (entity.tags.wikidata) return true;
79853 var preset = _mainPresetIndex.match(entity, context.graph());
79854 var isSuggestion = preset && preset.suggestion; // Lock the field if there is a value and a companion `*:wikidata` value
79856 var which = field.id; // 'brand', 'network', 'operator', 'flag'
79858 return isSuggestion && !!entity.tags[which] && !!entity.tags[which + ':wikidata'];
79861 field.locked(isLocked);
79864 function i(selection) {
79866 var isLocked = field.locked();
79867 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
79868 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
79869 input = wrap.selectAll('input').data([0]);
79870 input = input.enter().append('input').attr('type', field.type === 'identifier' ? 'text' : field.type).attr('id', field.domId).classed(field.type, true).call(utilNoAuto).merge(input);
79871 input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
79873 if (field.type === 'tel') {
79874 updatePhonePlaceholder();
79875 } else if (field.type === 'number') {
79876 var rtl = _mainLocalizer.textDirection() === 'rtl';
79877 input.attr('type', 'text');
79878 var inc = field.increment;
79879 var buttons = wrap.selectAll('.increment, .decrement').data(rtl ? [inc, -inc] : [-inc, inc]);
79880 buttons.enter().append('button').attr('class', function (d) {
79881 var which = d > 0 ? 'increment' : 'decrement';
79882 return 'form-field-button ' + which;
79883 }).merge(buttons).on('click', function (d3_event, d) {
79884 d3_event.preventDefault();
79885 var raw_vals = input.node().value || '0';
79886 var vals = raw_vals.split(';');
79887 vals = vals.map(function (v) {
79888 var num = parseFloat(v.trim(), 10);
79889 return isFinite(num) ? clamped(num + d) : v.trim();
79891 input.node().value = vals.join(';');
79894 } else if (field.type === 'identifier' && field.urlFormat && field.pattern) {
79895 input.attr('type', 'text');
79896 outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
79897 outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
79898 var domainResults = /^https?:\/\/(.{1,}?)\//.exec(field.urlFormat);
79900 if (domainResults.length >= 2 && domainResults[1]) {
79901 var domain = domainResults[1];
79902 return _t('icons.view_on', {
79908 }).on('click', function (d3_event) {
79909 d3_event.preventDefault();
79910 var value = validIdentifierValueForLink();
79913 var url = field.urlFormat.replace(/{value}/, encodeURIComponent(value));
79914 window.open(url, '_blank');
79916 }).merge(outlinkButton);
79917 } else if (field.type === 'url') {
79918 input.attr('type', 'text');
79919 outlinkButton = wrap.selectAll('.foreign-id-permalink').data([0]);
79920 outlinkButton.enter().append('button').call(svgIcon('#iD-icon-out-link')).attr('class', 'form-field-button foreign-id-permalink').attr('title', function () {
79921 return _t('icons.visit_website');
79922 }).on('click', function (d3_event) {
79923 d3_event.preventDefault();
79924 var value = validIdentifierValueForLink();
79925 if (value) window.open(value, '_blank');
79926 }).merge(outlinkButton);
79930 function updatePhonePlaceholder() {
79931 if (input.empty() || !Object.keys(_phoneFormats).length) return;
79932 var extent = combinedEntityExtent();
79933 var countryCode = extent && iso1A2Code(extent.center());
79935 var format = countryCode && _phoneFormats[countryCode.toLowerCase()];
79937 if (format) input.attr('placeholder', format);
79940 function validIdentifierValueForLink() {
79941 var value = utilGetSetValue(input).trim().split(';')[0];
79942 if (field.type === 'url' && value) return value;
79944 if (field.type === 'identifier' && field.pattern) {
79945 return value && value.match(new RegExp(field.pattern));
79949 } // clamp number to min/max
79952 function clamped(num) {
79953 if (field.minValue !== undefined) {
79954 num = Math.max(num, field.minValue);
79957 if (field.maxValue !== undefined) {
79958 num = Math.min(num, field.maxValue);
79964 function change(onInput) {
79965 return function () {
79967 var val = utilGetSetValue(input);
79968 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
79970 if (!val && Array.isArray(_tags[field.key])) return;
79973 if (field.type === 'number' && val) {
79974 var vals = val.split(';');
79975 vals = vals.map(function (v) {
79976 var num = parseFloat(v.trim(), 10);
79977 return isFinite(num) ? clamped(num) : v.trim();
79979 val = vals.join(';');
79982 utilGetSetValue(input, val);
79985 t[field.key] = val || undefined;
79986 dispatch.call('change', this, t, onInput);
79990 i.entityIDs = function (val) {
79991 if (!arguments.length) return _entityIDs;
79996 i.tags = function (tags) {
79998 var isMixed = Array.isArray(tags[field.key]);
79999 utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder() || _t('inspector.unknown')).classed('mixed', isMixed);
80001 if (outlinkButton && !outlinkButton.empty()) {
80002 var disabled = !validIdentifierValueForLink();
80003 outlinkButton.classed('disabled', disabled);
80007 i.focus = function () {
80008 var node = input.node();
80009 if (node) node.focus();
80012 function combinedEntityExtent() {
80013 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
80016 return utilRebind(i, dispatch, 'on');
80019 function uiFieldAccess(field, context) {
80020 var dispatch = dispatch$8('change');
80021 var items = select(null);
80025 function access(selection) {
80026 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80027 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80028 var list = wrap.selectAll('ul').data([0]);
80029 list = list.enter().append('ul').attr('class', 'rows').merge(list);
80030 items = list.selectAll('li').data(field.keys); // Enter
80032 var enter = items.enter().append('li').attr('class', function (d) {
80033 return 'labeled-input preset-access-' + d;
80035 enter.append('span').attr('class', 'label preset-label-access').attr('for', function (d) {
80036 return 'preset-input-access-' + d;
80037 }).html(function (d) {
80038 return field.t.html('types.' + d);
80040 enter.append('div').attr('class', 'preset-input-access-wrap').append('input').attr('type', 'text').attr('class', function (d) {
80041 return 'preset-input-access preset-input-access-' + d;
80042 }).call(utilNoAuto).each(function (d) {
80043 select(this).call(uiCombobox(context, 'access-' + d).data(access.options(d)));
80046 items = items.merge(enter);
80047 wrap.selectAll('.preset-input-access').on('change', change).on('blur', change);
80050 function change(d3_event, d) {
80052 var value = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
80054 if (!value && typeof _tags[d] !== 'string') return;
80055 tag[d] = value || undefined;
80056 dispatch.call('change', this, tag);
80059 access.options = function (type) {
80060 var options = ['no', 'permissive', 'private', 'permit', 'destination'];
80062 if (type !== 'access') {
80063 options.unshift('yes');
80064 options.push('designated');
80066 if (type === 'bicycle') {
80067 options.push('dismount');
80071 return options.map(function (option) {
80073 title: field.t('options.' + option + '.description'),
80079 var placeholdersByHighway = {
80081 foot: 'designated',
80082 motor_vehicle: 'no'
80086 motor_vehicle: 'no',
80092 motor_vehicle: 'no'
80095 motor_vehicle: 'no',
80096 bicycle: 'designated'
80099 motor_vehicle: 'no',
80100 horse: 'designated'
80104 motor_vehicle: 'no',
80110 motor_vehicle: 'yes',
80115 motor_vehicle: 'yes'
80119 motor_vehicle: 'yes',
80125 motor_vehicle: 'yes',
80131 motor_vehicle: 'yes',
80137 motor_vehicle: 'yes',
80143 motor_vehicle: 'yes',
80149 motor_vehicle: 'yes',
80155 motor_vehicle: 'yes',
80160 motor_vehicle: 'yes'
80164 motor_vehicle: 'yes',
80170 motor_vehicle: 'yes',
80176 motor_vehicle: 'yes',
80182 access.tags = function (tags) {
80184 utilGetSetValue(items.selectAll('.preset-input-access'), function (d) {
80185 return typeof tags[d] === 'string' ? tags[d] : '';
80186 }).classed('mixed', function (d) {
80187 return tags[d] && Array.isArray(tags[d]);
80188 }).attr('title', function (d) {
80189 return tags[d] && Array.isArray(tags[d]) && tags[d].filter(Boolean).join('\n');
80190 }).attr('placeholder', function (d) {
80191 if (tags[d] && Array.isArray(tags[d])) {
80192 return _t('inspector.multiple_values');
80195 if (d === 'access') {
80199 if (tags.access && typeof tags.access === 'string') {
80200 return tags.access;
80203 if (tags.highway) {
80204 if (typeof tags.highway === 'string') {
80205 if (placeholdersByHighway[tags.highway] && placeholdersByHighway[tags.highway][d]) {
80206 return placeholdersByHighway[tags.highway][d];
80209 var impliedAccesses = tags.highway.filter(Boolean).map(function (highwayVal) {
80210 return placeholdersByHighway[highwayVal] && placeholdersByHighway[highwayVal][d];
80211 }).filter(Boolean);
80213 if (impliedAccesses.length === tags.highway.length && new Set(impliedAccesses).size === 1) {
80214 // if all the highway values have the same implied access for this type then use that
80215 return impliedAccesses[0];
80220 return field.placeholder();
80224 access.focus = function () {
80225 items.selectAll('.preset-input-access').node().focus();
80228 return utilRebind(access, dispatch, 'on');
80231 function uiFieldAddress(field, context) {
80232 var dispatch = dispatch$8('change');
80234 var _selection = select(null);
80236 var _wrap = select(null);
80238 var addrField = _mainPresetIndex.field('address'); // needed for placeholder strings
80240 var _entityIDs = [];
80246 var _addressFormats = [{
80247 format: [['housenumber', 'street'], ['city', 'postcode']]
80249 _mainFileFetcher.get('address_formats').then(function (d) {
80250 _addressFormats = d;
80252 if (!_selection.empty()) {
80253 _selection.call(address);
80255 })["catch"](function () {
80259 function getNearStreets() {
80260 var extent = combinedEntityExtent();
80261 var l = extent.center();
80262 var box = geoExtent(l).padByMeters(200);
80263 var streets = context.history().intersects(box).filter(isAddressable).map(function (d) {
80264 var loc = context.projection([(extent[0][0] + extent[1][0]) / 2, (extent[0][1] + extent[1][1]) / 2]);
80265 var choice = geoChooseEdge(context.graph().childNodes(d), loc, context.projection);
80267 title: d.tags.name,
80268 value: d.tags.name,
80269 dist: choice.distance
80271 }).sort(function (a, b) {
80272 return a.dist - b.dist;
80274 return utilArrayUniqBy(streets, 'value');
80276 function isAddressable(d) {
80277 return d.tags.highway && d.tags.name && d.type === 'way';
80281 function getNearCities() {
80282 var extent = combinedEntityExtent();
80283 var l = extent.center();
80284 var box = geoExtent(l).padByMeters(200);
80285 var cities = context.history().intersects(box).filter(isAddressable).map(function (d) {
80287 title: d.tags['addr:city'] || d.tags.name,
80288 value: d.tags['addr:city'] || d.tags.name,
80289 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
80291 }).sort(function (a, b) {
80292 return a.dist - b.dist;
80294 return utilArrayUniqBy(cities, 'value');
80296 function isAddressable(d) {
80298 if (d.tags.admin_level === '8' && d.tags.boundary === 'administrative') return true;
80299 if (d.tags.border_type === 'city') return true;
80300 if (d.tags.place === 'city' || d.tags.place === 'town' || d.tags.place === 'village') return true;
80303 if (d.tags['addr:city']) return true;
80308 function getNearValues(key) {
80309 var extent = combinedEntityExtent();
80310 var l = extent.center();
80311 var box = geoExtent(l).padByMeters(200);
80312 var results = context.history().intersects(box).filter(function hasTag(d) {
80313 return _entityIDs.indexOf(d.id) === -1 && d.tags[key];
80314 }).map(function (d) {
80316 title: d.tags[key],
80317 value: d.tags[key],
80318 dist: geoSphericalDistance(d.extent(context.graph()).center(), l)
80320 }).sort(function (a, b) {
80321 return a.dist - b.dist;
80323 return utilArrayUniqBy(results, 'value');
80326 function updateForCountryCode() {
80327 if (!_countryCode) return;
80330 for (var i = 0; i < _addressFormats.length; i++) {
80331 var format = _addressFormats[i];
80333 if (!format.countryCodes) {
80334 addressFormat = format; // choose the default format, keep going
80335 } else if (format.countryCodes.indexOf(_countryCode) !== -1) {
80336 addressFormat = format; // choose the country format, stop here
80342 var dropdowns = addressFormat.dropdowns || ['city', 'county', 'country', 'district', 'hamlet', 'neighbourhood', 'place', 'postcode', 'province', 'quarter', 'state', 'street', 'subdistrict', 'suburb'];
80343 var widths = addressFormat.widths || {
80344 housenumber: 1 / 3,
80352 // Normalize widths.
80353 var total = r.reduce(function (sum, key) {
80354 return sum + (widths[key] || 0.5);
80356 return r.map(function (key) {
80359 width: (widths[key] || 0.5) / total
80364 var rows = _wrap.selectAll('.addr-row').data(addressFormat.format, function (d) {
80365 return d.toString();
80368 rows.exit().remove();
80369 rows.enter().append('div').attr('class', 'addr-row').selectAll('input').data(row).enter().append('input').property('type', 'text').call(updatePlaceholder).attr('class', function (d) {
80370 return 'addr-' + d.id;
80371 }).call(utilNoAuto).each(addDropdown).style('width', function (d) {
80372 return d.width * 100 + '%';
80375 function addDropdown(d) {
80376 if (dropdowns.indexOf(d.id) === -1) return; // not a dropdown
80378 var nearValues = d.id === 'street' ? getNearStreets : d.id === 'city' ? getNearCities : getNearValues;
80379 select(this).call(uiCombobox(context, 'address-' + d.id).minItems(1).caseSensitive(true).fetcher(function (value, callback) {
80380 callback(nearValues('addr:' + d.id));
80384 _wrap.selectAll('input').on('blur', change()).on('change', change());
80386 _wrap.selectAll('input:not(.combobox-input)').on('input', change(true));
80388 if (_tags) updateTags(_tags);
80391 function address(selection) {
80392 _selection = selection;
80393 _wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80394 _wrap = _wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(_wrap);
80395 var extent = combinedEntityExtent();
80400 if (context.inIntro()) {
80401 // localize the address format for the walkthrough
80402 countryCode = _t('intro.graph.countrycode');
80404 var center = extent.center();
80405 countryCode = iso1A2Code(center);
80409 _countryCode = countryCode.toLowerCase();
80410 updateForCountryCode();
80415 function change(onInput) {
80416 return function () {
80419 _wrap.selectAll('input').each(function (subfield) {
80420 var key = field.key + ':' + subfield.id;
80421 var value = this.value;
80422 if (!onInput) value = context.cleanTagValue(value); // don't override multiple values with blank string
80424 if (Array.isArray(_tags[key]) && !value) return;
80425 tags[key] = value || undefined;
80428 dispatch.call('change', this, tags, onInput);
80432 function updatePlaceholder(inputSelection) {
80433 return inputSelection.attr('placeholder', function (subfield) {
80434 if (_tags && Array.isArray(_tags[field.key + ':' + subfield.id])) {
80435 return _t('inspector.multiple_values');
80438 if (_countryCode) {
80439 var localkey = subfield.id + '!' + _countryCode;
80440 var tkey = addrField.hasTextForStringId('placeholders.' + localkey) ? localkey : subfield.id;
80441 return addrField.t('placeholders.' + tkey);
80446 function updateTags(tags) {
80447 utilGetSetValue(_wrap.selectAll('input'), function (subfield) {
80448 var val = tags[field.key + ':' + subfield.id];
80449 return typeof val === 'string' ? val : '';
80450 }).attr('title', function (subfield) {
80451 var val = tags[field.key + ':' + subfield.id];
80452 return val && Array.isArray(val) && val.filter(Boolean).join('\n');
80453 }).classed('mixed', function (subfield) {
80454 return Array.isArray(tags[field.key + ':' + subfield.id]);
80455 }).call(updatePlaceholder);
80458 function combinedEntityExtent() {
80459 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
80462 address.entityIDs = function (val) {
80463 if (!arguments.length) return _entityIDs;
80468 address.tags = function (tags) {
80473 address.focus = function () {
80474 var node = _wrap.selectAll('input').node();
80476 if (node) node.focus();
80479 return utilRebind(address, dispatch, 'on');
80482 function uiFieldCycleway(field, context) {
80483 var dispatch = dispatch$8('change');
80484 var items = select(null);
80485 var wrap = select(null);
80489 function cycleway(selection) {
80490 function stripcolon(s) {
80491 return s.replace(':', '');
80494 wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80495 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80496 var div = wrap.selectAll('ul').data([0]);
80497 div = div.enter().append('ul').attr('class', 'rows').merge(div);
80498 var keys = ['cycleway:left', 'cycleway:right'];
80499 items = div.selectAll('li').data(keys);
80500 var enter = items.enter().append('li').attr('class', function (d) {
80501 return 'labeled-input preset-cycleway-' + stripcolon(d);
80503 enter.append('span').attr('class', 'label preset-label-cycleway').attr('for', function (d) {
80504 return 'preset-input-cycleway-' + stripcolon(d);
80505 }).html(function (d) {
80506 return field.t.html('types.' + d);
80508 enter.append('div').attr('class', 'preset-input-cycleway-wrap').append('input').attr('type', 'text').attr('class', function (d) {
80509 return 'preset-input-cycleway preset-input-' + stripcolon(d);
80510 }).call(utilNoAuto).each(function (d) {
80511 select(this).call(uiCombobox(context, 'cycleway-' + stripcolon(d)).data(cycleway.options(d)));
80513 items = items.merge(enter); // Update
80515 wrap.selectAll('.preset-input-cycleway').on('change', change).on('blur', change);
80518 function change(d3_event, key) {
80519 var newValue = context.cleanTagValue(utilGetSetValue(select(this))); // don't override multiple values with blank string
80521 if (!newValue && (Array.isArray(_tags.cycleway) || Array.isArray(_tags[key]))) return;
80523 if (newValue === 'none' || newValue === '') {
80524 newValue = undefined;
80527 var otherKey = key === 'cycleway:left' ? 'cycleway:right' : 'cycleway:left';
80528 var otherValue = typeof _tags.cycleway === 'string' ? _tags.cycleway : _tags[otherKey];
80530 if (otherValue && Array.isArray(otherValue)) {
80531 // we must always have an explicit value for comparison
80532 otherValue = otherValue[0];
80535 if (otherValue === 'none' || otherValue === '') {
80536 otherValue = undefined;
80539 var tag = {}; // If the left and right tags match, use the cycleway tag to tag both
80540 // sides the same way
80542 if (newValue === otherValue) {
80544 cycleway: newValue,
80545 'cycleway:left': undefined,
80546 'cycleway:right': undefined
80549 // Always set both left and right as changing one can affect the other
80551 cycleway: undefined
80553 tag[key] = newValue;
80554 tag[otherKey] = otherValue;
80557 dispatch.call('change', this, tag);
80560 cycleway.options = function () {
80561 return field.options.map(function (option) {
80563 title: field.t('options.' + option + '.description'),
80569 cycleway.tags = function (tags) {
80570 _tags = tags; // If cycleway is set, use that instead of individual values
80572 var commonValue = typeof tags.cycleway === 'string' && tags.cycleway;
80573 utilGetSetValue(items.selectAll('.preset-input-cycleway'), function (d) {
80574 if (commonValue) return commonValue;
80575 return !tags.cycleway && typeof tags[d] === 'string' ? tags[d] : '';
80576 }).attr('title', function (d) {
80577 if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
80580 if (Array.isArray(tags.cycleway)) {
80581 vals = vals.concat(tags.cycleway);
80584 if (Array.isArray(tags[d])) {
80585 vals = vals.concat(tags[d]);
80588 return vals.filter(Boolean).join('\n');
80592 }).attr('placeholder', function (d) {
80593 if (Array.isArray(tags.cycleway) || Array.isArray(tags[d])) {
80594 return _t('inspector.multiple_values');
80597 return field.placeholder();
80598 }).classed('mixed', function (d) {
80599 return Array.isArray(tags.cycleway) || Array.isArray(tags[d]);
80603 cycleway.focus = function () {
80604 var node = wrap.selectAll('input').node();
80605 if (node) node.focus();
80608 return utilRebind(cycleway, dispatch, 'on');
80611 function uiFieldLanes(field, context) {
80612 var dispatch = dispatch$8('change');
80613 var LANE_WIDTH = 40;
80614 var LANE_HEIGHT = 200;
80615 var _entityIDs = [];
80617 function lanes(selection) {
80618 var lanesData = context.entity(_entityIDs[0]).lanes();
80620 if (!context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
80621 selection.call(lanes.off);
80625 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
80626 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80627 var surface = wrap.selectAll('.surface').data([0]);
80628 var d = utilGetDimensions(wrap);
80629 var freeSpace = d[0] - lanesData.lanes.length * LANE_WIDTH * 1.5 + LANE_WIDTH * 0.5;
80630 surface = surface.enter().append('svg').attr('width', d[0]).attr('height', 300).attr('class', 'surface').merge(surface);
80631 var lanesSelection = surface.selectAll('.lanes').data([0]);
80632 lanesSelection = lanesSelection.enter().append('g').attr('class', 'lanes').merge(lanesSelection);
80633 lanesSelection.attr('transform', function () {
80634 return 'translate(' + freeSpace / 2 + ', 0)';
80636 var lane = lanesSelection.selectAll('.lane').data(lanesData.lanes);
80637 lane.exit().remove();
80638 var enter = lane.enter().append('g').attr('class', 'lane');
80639 enter.append('g').append('rect').attr('y', 50).attr('width', LANE_WIDTH).attr('height', LANE_HEIGHT);
80640 enter.append('g').attr('class', 'forward').append('text').attr('y', 40).attr('x', 14).html('▲');
80641 enter.append('g').attr('class', 'bothways').append('text').attr('y', 40).attr('x', 14).html('▲▼');
80642 enter.append('g').attr('class', 'backward').append('text').attr('y', 40).attr('x', 14).html('▼');
80643 lane = lane.merge(enter);
80644 lane.attr('transform', function (d) {
80645 return 'translate(' + LANE_WIDTH * d.index * 1.5 + ', 0)';
80647 lane.select('.forward').style('visibility', function (d) {
80648 return d.direction === 'forward' ? 'visible' : 'hidden';
80650 lane.select('.bothways').style('visibility', function (d) {
80651 return d.direction === 'bothways' ? 'visible' : 'hidden';
80653 lane.select('.backward').style('visibility', function (d) {
80654 return d.direction === 'backward' ? 'visible' : 'hidden';
80658 lanes.entityIDs = function (val) {
80662 lanes.tags = function () {};
80664 lanes.focus = function () {};
80666 lanes.off = function () {};
80668 return utilRebind(lanes, dispatch, 'on');
80670 uiFieldLanes.supportsMultiselection = false;
80672 var _languagesArray = [];
80673 function uiFieldLocalized(field, context) {
80674 var dispatch = dispatch$8('change', 'input');
80675 var wikipedia = services.wikipedia;
80676 var input = select(null);
80677 var localizedInputs = select(null);
80681 var _tags; // A concern here in switching to async data means that _languagesArray will not
80682 // be available the first time through, so things like the fetchers and
80683 // the language() function will not work immediately.
80686 _mainFileFetcher.get('languages').then(loadLanguagesArray)["catch"](function () {
80689 var _territoryLanguages = {};
80690 _mainFileFetcher.get('territory_languages').then(function (d) {
80691 _territoryLanguages = d;
80692 })["catch"](function () {
80694 }); // reuse these combos
80696 var langCombo = uiCombobox(context, 'localized-lang').fetcher(fetchLanguages).minItems(0);
80698 var _selection = select(null);
80700 var _multilingual = [];
80702 var _buttonTip = uiTooltip().title(_t.html('translate.translate')).placement('left');
80706 var _entityIDs = [];
80708 function loadLanguagesArray(dataLanguages) {
80709 if (_languagesArray.length !== 0) return; // some conversion is needed to ensure correct OSM tags are used
80711 var replacements = {
80713 // in OSM, `sr` implies Cyrillic
80714 'sr-Cyrl': false // `sr-Cyrl` isn't used in OSM
80718 for (var code in dataLanguages) {
80719 if (replacements[code] === false) continue;
80720 var metaCode = code;
80721 if (replacements[code]) metaCode = replacements[code];
80723 _languagesArray.push({
80724 localName: _mainLocalizer.languageName(metaCode, {
80727 nativeName: dataLanguages[metaCode].nativeName,
80729 label: _mainLocalizer.languageName(metaCode)
80734 function calcLocked() {
80735 // Protect name field for suggestion presets that don't display a brand/operator field
80736 var isLocked = field.id === 'name' && _entityIDs.length && _entityIDs.some(function (entityID) {
80737 var entity = context.graph().hasEntity(entityID);
80738 if (!entity) return false; // Features linked to Wikidata are likely important and should be protected
80740 if (entity.tags.wikidata) return true; // Assume the name has already been confirmed if its source has been researched
80742 if (entity.tags['name:etymology:wikidata']) return true; // Lock the `name` if this is a suggestion preset that assigns the name,
80743 // and the preset does not display a `brand` or `operator` field.
80744 // (For presets like hotels, car dealerships, post offices, the `name` should remain editable)
80745 // see also similar logic in `outdated_tags.js`
80747 var preset = _mainPresetIndex.match(entity, context.graph());
80750 var isSuggestion = preset.suggestion;
80751 var fields = preset.fields();
80752 var showsBrandField = fields.some(function (d) {
80753 return d.id === 'brand';
80755 var showsOperatorField = fields.some(function (d) {
80756 return d.id === 'operator';
80758 var setsName = preset.addTags.name;
80759 var setsBrandWikidata = preset.addTags['brand:wikidata'];
80760 var setsOperatorWikidata = preset.addTags['operator:wikidata'];
80761 return isSuggestion && setsName && (setsBrandWikidata && !showsBrandField || setsOperatorWikidata && !showsOperatorField);
80767 field.locked(isLocked);
80768 } // update _multilingual, maintaining the existing order
80771 function calcMultilingual(tags) {
80772 var existingLangsOrdered = _multilingual.map(function (item) {
80776 var existingLangs = new Set(existingLangsOrdered.filter(Boolean));
80778 for (var k in tags) {
80779 var m = k.match(/^(.*):(.*)$/);
80781 if (m && m[1] === field.key && m[2]) {
80787 if (existingLangs.has(item.lang)) {
80788 // update the value
80789 _multilingual[existingLangsOrdered.indexOf(item.lang)].value = item.value;
80790 existingLangs["delete"](item.lang);
80792 _multilingual.push(item);
80795 } // Don't remove items based on deleted tags, since this makes the UI
80796 // disappear unexpectedly when clearing values - #8164
80799 _multilingual.forEach(function (item) {
80800 if (item.lang && existingLangs.has(item.lang)) {
80806 function localized(selection) {
80807 _selection = selection;
80809 var isLocked = field.locked();
80810 var wrap = selection.selectAll('.form-field-input-wrap').data([0]); // enter/update
80812 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
80813 input = wrap.selectAll('.localized-main').data([0]); // enter/update
80815 input = input.enter().append('input').attr('type', 'text').attr('id', field.domId).attr('class', 'localized-main').call(utilNoAuto).merge(input);
80816 input.classed('disabled', !!isLocked).attr('readonly', isLocked || null).on('input', change(true)).on('blur', change()).on('change', change());
80817 var translateButton = wrap.selectAll('.localized-add').data([0]);
80818 translateButton = translateButton.enter().append('button').attr('class', 'localized-add form-field-button').call(svgIcon('#iD-icon-plus')).merge(translateButton);
80819 translateButton.classed('disabled', !!isLocked).call(isLocked ? _buttonTip.destroy : _buttonTip).on('click', addNew);
80821 if (_tags && !_multilingual.length) {
80822 calcMultilingual(_tags);
80825 localizedInputs = selection.selectAll('.localized-multilingual').data([0]);
80826 localizedInputs = localizedInputs.enter().append('div').attr('class', 'localized-multilingual').merge(localizedInputs);
80827 localizedInputs.call(renderMultilingual);
80828 localizedInputs.selectAll('button, input').classed('disabled', !!isLocked).attr('readonly', isLocked || null);
80830 function addNew(d3_event) {
80831 d3_event.preventDefault();
80832 if (field.locked()) return;
80833 var defaultLang = _mainLocalizer.languageCode().toLowerCase();
80835 var langExists = _multilingual.find(function (datum) {
80836 return datum.lang === defaultLang;
80839 var isLangEn = defaultLang.indexOf('en') > -1;
80841 if (isLangEn || langExists) {
80843 langExists = _multilingual.find(function (datum) {
80844 return datum.lang === defaultLang;
80849 // prepend the value so it appears at the top
80850 _multilingual.unshift({
80855 localizedInputs.call(renderMultilingual);
80859 function change(onInput) {
80860 return function (d3_event) {
80861 if (field.locked()) {
80862 d3_event.preventDefault();
80866 var val = utilGetSetValue(select(this));
80867 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
80869 if (!val && Array.isArray(_tags[field.key])) return;
80871 t[field.key] = val || undefined;
80872 dispatch.call('change', this, t, onInput);
80877 function key(lang) {
80878 return field.key + ':' + lang;
80881 function changeLang(d3_event, d) {
80882 var tags = {}; // make sure unrecognized suffixes are lowercase - #7156
80884 var lang = utilGetSetValue(select(this)).toLowerCase();
80886 var language = _languagesArray.find(function (d) {
80887 return d.label.toLowerCase() === lang || d.localName && d.localName.toLowerCase() === lang || d.nativeName && d.nativeName.toLowerCase() === lang;
80890 if (language) lang = language.code;
80892 if (d.lang && d.lang !== lang) {
80893 tags[key(d.lang)] = undefined;
80896 var newKey = lang && context.cleanTagKey(key(lang));
80897 var value = utilGetSetValue(select(this.parentNode).selectAll('.localized-value'));
80899 if (newKey && value) {
80900 tags[newKey] = value;
80901 } else if (newKey && _wikiTitles && _wikiTitles[d.lang]) {
80902 tags[newKey] = _wikiTitles[d.lang];
80906 dispatch.call('change', this, tags);
80909 function changeValue(d3_event, d) {
80910 if (!d.lang) return;
80911 var value = context.cleanTagValue(utilGetSetValue(select(this))) || undefined; // don't override multiple values with blank string
80913 if (!value && Array.isArray(d.value)) return;
80915 t[key(d.lang)] = value;
80917 dispatch.call('change', this, t);
80920 function fetchLanguages(value, cb) {
80921 var v = value.toLowerCase(); // show the user's language first
80923 var langCodes = [_mainLocalizer.localeCode(), _mainLocalizer.languageCode()];
80925 if (_countryCode && _territoryLanguages[_countryCode]) {
80926 langCodes = langCodes.concat(_territoryLanguages[_countryCode]);
80929 var langItems = [];
80930 langCodes.forEach(function (code) {
80931 var langItem = _languagesArray.find(function (item) {
80932 return item.code === code;
80935 if (langItem) langItems.push(langItem);
80937 langItems = utilArrayUniq(langItems.concat(_languagesArray));
80938 cb(langItems.filter(function (d) {
80939 return d.label.toLowerCase().indexOf(v) >= 0 || d.localName && d.localName.toLowerCase().indexOf(v) >= 0 || d.nativeName && d.nativeName.toLowerCase().indexOf(v) >= 0 || d.code.toLowerCase().indexOf(v) >= 0;
80940 }).map(function (d) {
80947 function renderMultilingual(selection) {
80948 var entries = selection.selectAll('div.entry').data(_multilingual, function (d) {
80951 entries.exit().style('top', '0').style('max-height', '240px').transition().duration(200).style('opacity', '0').style('max-height', '0px').remove();
80952 var entriesEnter = entries.enter().append('div').attr('class', 'entry').each(function (_, index) {
80953 var wrap = select(this);
80954 var domId = utilUniqueDomId(index);
80955 var label = wrap.append('label').attr('class', 'field-label').attr('for', domId);
80956 var text = label.append('span').attr('class', 'label-text');
80957 text.append('span').attr('class', 'label-textvalue').html(_t.html('translate.localized_translation_label'));
80958 text.append('span').attr('class', 'label-textannotation');
80959 label.append('button').attr('class', 'remove-icon-multilingual').on('click', function (d3_event, d) {
80960 if (field.locked()) return;
80961 d3_event.preventDefault(); // remove the UI item manually
80963 _multilingual.splice(_multilingual.indexOf(d), 1);
80965 var langKey = d.lang && key(d.lang);
80967 if (langKey && langKey in _tags) {
80968 delete _tags[langKey]; // remove from entity tags
80971 t[langKey] = undefined;
80972 dispatch.call('change', this, t);
80976 renderMultilingual(selection);
80977 }).call(svgIcon('#iD-operation-delete'));
80978 wrap.append('input').attr('class', 'localized-lang').attr('id', domId).attr('type', 'text').attr('placeholder', _t('translate.localized_translation_language')).on('blur', changeLang).on('change', changeLang).call(langCombo);
80979 wrap.append('input').attr('type', 'text').attr('class', 'localized-value').on('blur', changeValue).on('change', changeValue);
80981 entriesEnter.style('margin-top', '0px').style('max-height', '0px').style('opacity', '0').transition().duration(200).style('margin-top', '10px').style('max-height', '240px').style('opacity', '1').on('end', function () {
80982 select(this).style('max-height', '').style('overflow', 'visible');
80984 entries = entries.merge(entriesEnter);
80985 entries.order(); // allow removing the entry UIs even if there isn't a tag to remove
80987 entries.classed('present', true);
80988 utilGetSetValue(entries.select('.localized-lang'), function (d) {
80989 var langItem = _languagesArray.find(function (item) {
80990 return item.code === d.lang;
80993 if (langItem) return langItem.label;
80996 utilGetSetValue(entries.select('.localized-value'), function (d) {
80997 return typeof d.value === 'string' ? d.value : '';
80998 }).attr('title', function (d) {
80999 return Array.isArray(d.value) ? d.value.filter(Boolean).join('\n') : null;
81000 }).attr('placeholder', function (d) {
81001 return Array.isArray(d.value) ? _t('inspector.multiple_values') : _t('translate.localized_translation_name');
81002 }).classed('mixed', function (d) {
81003 return Array.isArray(d.value);
81007 localized.tags = function (tags) {
81008 _tags = tags; // Fetch translations from wikipedia
81010 if (typeof tags.wikipedia === 'string' && !_wikiTitles) {
81012 var wm = tags.wikipedia.match(/([^:]+):(.+)/);
81014 if (wm && wm[0] && wm[1]) {
81015 wikipedia.translations(wm[1], wm[2], function (err, d) {
81016 if (err || !d) return;
81022 var isMixed = Array.isArray(tags[field.key]);
81023 utilGetSetValue(input, typeof tags[field.key] === 'string' ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder()).classed('mixed', isMixed);
81024 calcMultilingual(tags);
81026 _selection.call(localized);
81029 localized.focus = function () {
81030 input.node().focus();
81033 localized.entityIDs = function (val) {
81034 if (!arguments.length) return _entityIDs;
81036 _multilingual = [];
81041 function loadCountryCode() {
81042 var extent = combinedEntityExtent();
81043 var countryCode = extent && iso1A2Code(extent.center());
81044 _countryCode = countryCode && countryCode.toLowerCase();
81047 function combinedEntityExtent() {
81048 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81051 return utilRebind(localized, dispatch, 'on');
81054 function uiFieldRoadheight(field, context) {
81055 var dispatch = dispatch$8('change');
81056 var primaryUnitInput = select(null);
81057 var primaryInput = select(null);
81058 var secondaryInput = select(null);
81059 var secondaryUnitInput = select(null);
81060 var _entityIDs = [];
81066 var primaryUnits = [{
81068 title: _t('inspector.roadheight.meter')
81071 title: _t('inspector.roadheight.foot')
81073 var unitCombo = uiCombobox(context, 'roadheight-unit').data(primaryUnits);
81075 function roadheight(selection) {
81076 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81077 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81078 primaryInput = wrap.selectAll('input.roadheight-number').data([0]);
81079 primaryInput = primaryInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-number').attr('id', field.domId).call(utilNoAuto).merge(primaryInput);
81080 primaryInput.on('change', change).on('blur', change);
81081 var loc = combinedEntityExtent().center();
81082 _isImperial = roadHeightUnit(loc) === 'ft';
81083 primaryUnitInput = wrap.selectAll('input.roadheight-unit').data([0]);
81084 primaryUnitInput = primaryUnitInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-unit').call(unitCombo).merge(primaryUnitInput);
81085 primaryUnitInput.on('blur', changeUnits).on('change', changeUnits);
81086 secondaryInput = wrap.selectAll('input.roadheight-secondary-number').data([0]);
81087 secondaryInput = secondaryInput.enter().append('input').attr('type', 'text').attr('class', 'roadheight-secondary-number').call(utilNoAuto).merge(secondaryInput);
81088 secondaryInput.on('change', change).on('blur', change);
81089 secondaryUnitInput = wrap.selectAll('input.roadheight-secondary-unit').data([0]);
81090 secondaryUnitInput = secondaryUnitInput.enter().append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', true).classed('roadheight-secondary-unit', true).attr('readonly', 'readonly').merge(secondaryUnitInput);
81092 function changeUnits() {
81093 _isImperial = utilGetSetValue(primaryUnitInput) === 'ft';
81094 utilGetSetValue(primaryUnitInput, _isImperial ? 'ft' : 'm');
81095 setUnitSuggestions();
81100 function setUnitSuggestions() {
81101 utilGetSetValue(primaryUnitInput, _isImperial ? 'ft' : 'm');
81104 function change() {
81106 var primaryValue = utilGetSetValue(primaryInput).trim();
81107 var secondaryValue = utilGetSetValue(secondaryInput).trim(); // don't override multiple values with blank string
81109 if (!primaryValue && !secondaryValue && Array.isArray(_tags[field.key])) return;
81111 if (!primaryValue && !secondaryValue) {
81112 tag[field.key] = undefined;
81113 } else if (isNaN(primaryValue) || isNaN(secondaryValue) || !_isImperial) {
81114 tag[field.key] = context.cleanTagValue(primaryValue);
81116 if (primaryValue !== '') {
81117 primaryValue = context.cleanTagValue(primaryValue + '\'');
81120 if (secondaryValue !== '') {
81121 secondaryValue = context.cleanTagValue(secondaryValue + '"');
81124 tag[field.key] = primaryValue + secondaryValue;
81127 dispatch.call('change', this, tag);
81130 roadheight.tags = function (tags) {
81132 var primaryValue = tags[field.key];
81133 var secondaryValue;
81134 var isMixed = Array.isArray(primaryValue);
81137 if (primaryValue && (primaryValue.indexOf('\'') >= 0 || primaryValue.indexOf('"') >= 0)) {
81138 secondaryValue = primaryValue.match(/(-?[\d.]+)"/);
81140 if (secondaryValue !== null) {
81141 secondaryValue = secondaryValue[1];
81144 primaryValue = primaryValue.match(/(-?[\d.]+)'/);
81146 if (primaryValue !== null) {
81147 primaryValue = primaryValue[1];
81150 _isImperial = true;
81151 } else if (primaryValue) {
81152 _isImperial = false;
81156 setUnitSuggestions();
81157 utilGetSetValue(primaryInput, typeof primaryValue === 'string' ? primaryValue : '').attr('title', isMixed ? primaryValue.filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : _t('inspector.unknown')).classed('mixed', isMixed);
81158 utilGetSetValue(secondaryInput, typeof secondaryValue === 'string' ? secondaryValue : '').attr('placeholder', isMixed ? _t('inspector.multiple_values') : _isImperial ? '0' : null).classed('mixed', isMixed).classed('disabled', !_isImperial).attr('readonly', _isImperial ? null : 'readonly');
81159 secondaryUnitInput.attr('value', _isImperial ? _t('inspector.roadheight.inch') : null);
81162 roadheight.focus = function () {
81163 primaryInput.node().focus();
81166 roadheight.entityIDs = function (val) {
81170 function combinedEntityExtent() {
81171 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81174 return utilRebind(roadheight, dispatch, 'on');
81177 function uiFieldRoadspeed(field, context) {
81178 var dispatch = dispatch$8('change');
81179 var unitInput = select(null);
81180 var input = select(null);
81181 var _entityIDs = [];
81187 var speedCombo = uiCombobox(context, 'roadspeed');
81188 var unitCombo = uiCombobox(context, 'roadspeed-unit').data(['km/h', 'mph'].map(comboValues));
81189 var metricValues = [20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120];
81190 var imperialValues = [5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80];
81192 function roadspeed(selection) {
81193 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81194 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81195 input = wrap.selectAll('input.roadspeed-number').data([0]);
81196 input = input.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-number').attr('id', field.domId).call(utilNoAuto).call(speedCombo).merge(input);
81197 input.on('change', change).on('blur', change);
81198 var loc = combinedEntityExtent().center();
81199 _isImperial = roadSpeedUnit(loc) === 'mph';
81200 unitInput = wrap.selectAll('input.roadspeed-unit').data([0]);
81201 unitInput = unitInput.enter().append('input').attr('type', 'text').attr('class', 'roadspeed-unit').call(unitCombo).merge(unitInput);
81202 unitInput.on('blur', changeUnits).on('change', changeUnits);
81204 function changeUnits() {
81205 _isImperial = utilGetSetValue(unitInput) === 'mph';
81206 utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
81207 setUnitSuggestions();
81212 function setUnitSuggestions() {
81213 speedCombo.data((_isImperial ? imperialValues : metricValues).map(comboValues));
81214 utilGetSetValue(unitInput, _isImperial ? 'mph' : 'km/h');
81217 function comboValues(d) {
81219 value: d.toString(),
81220 title: d.toString()
81224 function change() {
81226 var value = utilGetSetValue(input).trim(); // don't override multiple values with blank string
81228 if (!value && Array.isArray(_tags[field.key])) return;
81231 tag[field.key] = undefined;
81232 } else if (isNaN(value) || !_isImperial) {
81233 tag[field.key] = context.cleanTagValue(value);
81235 tag[field.key] = context.cleanTagValue(value + ' mph');
81238 dispatch.call('change', this, tag);
81241 roadspeed.tags = function (tags) {
81243 var value = tags[field.key];
81244 var isMixed = Array.isArray(value);
81247 if (value && value.indexOf('mph') >= 0) {
81248 value = parseInt(value, 10).toString();
81249 _isImperial = true;
81250 } else if (value) {
81251 _isImperial = false;
81255 setUnitSuggestions();
81256 utilGetSetValue(input, typeof value === 'string' ? value : '').attr('title', isMixed ? value.filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder()).classed('mixed', isMixed);
81259 roadspeed.focus = function () {
81260 input.node().focus();
81263 roadspeed.entityIDs = function (val) {
81267 function combinedEntityExtent() {
81268 return _entityIDs && _entityIDs.length && utilTotalExtent(_entityIDs, context.graph());
81271 return utilRebind(roadspeed, dispatch, 'on');
81274 function uiFieldRadio(field, context) {
81275 var dispatch = dispatch$8('change');
81276 var placeholder = select(null);
81277 var wrap = select(null);
81278 var labels = select(null);
81279 var radios = select(null);
81280 var radioData = (field.options || field.keys).slice(); // shallow copy
81285 var _entityIDs = [];
81287 function selectedKey() {
81288 var node = wrap.selectAll('.form-field-input-radio label.active input');
81289 return !node.empty() && node.datum();
81292 function radio(selection) {
81293 selection.classed('preset-radio', true);
81294 wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81295 var enter = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-radio');
81296 enter.append('span').attr('class', 'placeholder');
81297 wrap = wrap.merge(enter);
81298 placeholder = wrap.selectAll('.placeholder');
81299 labels = wrap.selectAll('label').data(radioData);
81300 enter = labels.enter().append('label');
81301 enter.append('input').attr('type', 'radio').attr('name', field.id).attr('value', function (d) {
81302 return field.t('options.' + d, {
81305 }).attr('checked', false);
81306 enter.append('span').html(function (d) {
81307 return field.t.html('options.' + d, {
81311 labels = labels.merge(enter);
81312 radios = labels.selectAll('input').on('change', changeRadio);
81315 function structureExtras(selection, tags) {
81316 var selected = selectedKey() || tags.layer !== undefined;
81317 var type = _mainPresetIndex.field(selected);
81318 var layer = _mainPresetIndex.field('layer');
81319 var showLayer = selected === 'bridge' || selected === 'tunnel' || tags.layer !== undefined;
81320 var extrasWrap = selection.selectAll('.structure-extras-wrap').data(selected ? [0] : []);
81321 extrasWrap.exit().remove();
81322 extrasWrap = extrasWrap.enter().append('div').attr('class', 'structure-extras-wrap').merge(extrasWrap);
81323 var list = extrasWrap.selectAll('ul').data([0]);
81324 list = list.enter().append('ul').attr('class', 'rows').merge(list); // Type
81327 if (!typeField || typeField.id !== selected) {
81328 typeField = uiField(context, type, _entityIDs, {
81330 }).on('change', changeType);
81333 typeField.tags(tags);
81338 var typeItem = list.selectAll('.structure-type-item').data(typeField ? [typeField] : [], function (d) {
81342 typeItem.exit().remove(); // Enter
81344 var typeEnter = typeItem.enter().insert('li', ':first-child').attr('class', 'labeled-input structure-type-item');
81345 typeEnter.append('span').attr('class', 'label structure-label-type').attr('for', 'preset-input-' + selected).html(_t.html('inspector.radio.structure.type'));
81346 typeEnter.append('div').attr('class', 'structure-input-type-wrap'); // Update
81348 typeItem = typeItem.merge(typeEnter);
81351 typeItem.selectAll('.structure-input-type-wrap').call(typeField.render);
81355 if (layer && showLayer) {
81357 layerField = uiField(context, layer, _entityIDs, {
81359 }).on('change', changeLayer);
81362 layerField.tags(tags);
81363 field.keys = utilArrayUnion(field.keys, ['layer']);
81366 field.keys = field.keys.filter(function (k) {
81367 return k !== 'layer';
81371 var layerItem = list.selectAll('.structure-layer-item').data(layerField ? [layerField] : []); // Exit
81373 layerItem.exit().remove(); // Enter
81375 var layerEnter = layerItem.enter().append('li').attr('class', 'labeled-input structure-layer-item');
81376 layerEnter.append('span').attr('class', 'label structure-label-layer').attr('for', 'preset-input-layer').html(_t.html('inspector.radio.structure.layer'));
81377 layerEnter.append('div').attr('class', 'structure-input-layer-wrap'); // Update
81379 layerItem = layerItem.merge(layerEnter);
81382 layerItem.selectAll('.structure-input-layer-wrap').call(layerField.render);
81386 function changeType(t, onInput) {
81387 var key = selectedKey();
81391 if (val !== 'no') {
81392 _oldType[key] = val;
81395 if (field.type === 'structureRadio') {
81396 // remove layer if it should not be set
81397 if (val === 'no' || key !== 'bridge' && key !== 'tunnel' || key === 'tunnel' && val === 'building_passage') {
81398 t.layer = undefined;
81399 } // add layer if it should be set
81402 if (t.layer === undefined) {
81403 if (key === 'bridge' && val !== 'no') {
81407 if (key === 'tunnel' && val !== 'no' && val !== 'building_passage') {
81413 dispatch.call('change', this, t, onInput);
81416 function changeLayer(t, onInput) {
81417 if (t.layer === '0') {
81418 t.layer = undefined;
81421 dispatch.call('change', this, t, onInput);
81424 function changeRadio() {
81429 t[field.key] = undefined;
81432 radios.each(function (d) {
81433 var active = select(this).property('checked');
81434 if (active) activeKey = d;
81437 if (active) t[field.key] = d;
81439 var val = _oldType[activeKey] || 'yes';
81440 t[d] = active ? val : undefined;
81444 if (field.type === 'structureRadio') {
81445 if (activeKey === 'bridge') {
81447 } else if (activeKey === 'tunnel' && t.tunnel !== 'building_passage') {
81450 t.layer = undefined;
81454 dispatch.call('change', this, t);
81457 radio.tags = function (tags) {
81458 radios.property('checked', function (d) {
81460 return tags[field.key] === d;
81463 return !!(typeof tags[d] === 'string' && tags[d].toLowerCase() !== 'no');
81466 function isMixed(d) {
81468 return Array.isArray(tags[field.key]) && tags[field.key].includes(d);
81471 return Array.isArray(tags[d]);
81474 labels.classed('active', function (d) {
81476 return Array.isArray(tags[field.key]) && tags[field.key].includes(d) || tags[field.key] === d;
81479 return Array.isArray(tags[d]) || !!(tags[d] && tags[d].toLowerCase() !== 'no');
81480 }).classed('mixed', isMixed).attr('title', function (d) {
81481 return isMixed(d) ? _t('inspector.unshared_value_tooltip') : null;
81483 var selection = radios.filter(function () {
81484 return this.checked;
81487 if (selection.empty()) {
81488 placeholder.html(_t.html('inspector.none'));
81490 placeholder.html(selection.attr('value'));
81491 _oldType[selection.datum()] = tags[selection.datum()];
81494 if (field.type === 'structureRadio') {
81495 // For waterways without a tunnel tag, set 'culvert' as
81496 // the _oldType to default to if the user picks 'tunnel'
81497 if (!!tags.waterway && !_oldType.tunnel) {
81498 _oldType.tunnel = 'culvert';
81501 wrap.call(structureExtras, tags);
81505 radio.focus = function () {
81506 radios.node().focus();
81509 radio.entityIDs = function (val) {
81510 if (!arguments.length) return _entityIDs;
81516 radio.isAllowed = function () {
81517 return _entityIDs.length === 1;
81520 return utilRebind(radio, dispatch, 'on');
81523 function uiFieldRestrictions(field, context) {
81524 var dispatch = dispatch$8('change');
81525 var breathe = behaviorBreathe();
81526 corePreferences('turn-restriction-via-way', null); // remove old key
81528 var storedViaWay = corePreferences('turn-restriction-via-way0'); // use new key #6922
81530 var storedDistance = corePreferences('turn-restriction-distance');
81532 var _maxViaWay = storedViaWay !== null ? +storedViaWay : 0;
81534 var _maxDistance = storedDistance ? +storedDistance : 30;
81536 var _initialized = false;
81538 var _parent = select(null); // the entire field
81541 var _container = select(null); // just the map
81556 function restrictions(selection) {
81557 _parent = selection; // try to reuse the intersection, but always rebuild it if the graph has changed
81559 if (_vertexID && (context.graph() !== _graph || !_intersection)) {
81560 _graph = context.graph();
81561 _intersection = osmIntersection(_graph, _vertexID, _maxDistance);
81562 } // It's possible for there to be no actual intersection here.
81563 // for example, a vertex of two `highway=path`
81564 // In this case, hide the field.
81567 var isOK = _intersection && _intersection.vertices.length && // has vertices
81568 _intersection.vertices // has the vertex that the user selected
81569 .filter(function (vertex) {
81570 return vertex.id === _vertexID;
81571 }).length && _intersection.ways.length > 2 && // has more than 2 ways
81572 _intersection.ways // has more than 1 TO way
81573 .filter(function (way) {
81575 }).length > 1; // Also hide in the case where
81577 select(selection.node().parentNode).classed('hide', !isOK); // if form field is hidden or has detached from dom, clean up.
81579 if (!isOK || !context.container().select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode || !selection.node().parentNode.parentNode) {
81580 selection.call(restrictions.off);
81584 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
81585 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
81586 var container = wrap.selectAll('.restriction-container').data([0]); // enter
81588 var containerEnter = container.enter().append('div').attr('class', 'restriction-container');
81589 containerEnter.append('div').attr('class', 'restriction-help'); // update
81591 _container = containerEnter.merge(container).call(renderViewer);
81592 var controls = wrap.selectAll('.restriction-controls').data([0]); // enter/update
81594 controls.enter().append('div').attr('class', 'restriction-controls-container').append('div').attr('class', 'restriction-controls').merge(controls).call(renderControls);
81597 function renderControls(selection) {
81598 var distControl = selection.selectAll('.restriction-distance').data([0]);
81599 distControl.exit().remove();
81600 var distControlEnter = distControl.enter().append('div').attr('class', 'restriction-control restriction-distance');
81601 distControlEnter.append('span').attr('class', 'restriction-control-label restriction-distance-label').html(_t.html('restriction.controls.distance') + ':');
81602 distControlEnter.append('input').attr('class', 'restriction-distance-input').attr('type', 'range').attr('min', '20').attr('max', '50').attr('step', '5');
81603 distControlEnter.append('span').attr('class', 'restriction-distance-text'); // update
81605 selection.selectAll('.restriction-distance-input').property('value', _maxDistance).on('input', function () {
81606 var val = select(this).property('value');
81607 _maxDistance = +val;
81608 _intersection = null;
81610 _container.selectAll('.layer-osm .layer-turns *').remove();
81612 corePreferences('turn-restriction-distance', _maxDistance);
81614 _parent.call(restrictions);
81616 selection.selectAll('.restriction-distance-text').html(displayMaxDistance(_maxDistance));
81617 var viaControl = selection.selectAll('.restriction-via-way').data([0]);
81618 viaControl.exit().remove();
81619 var viaControlEnter = viaControl.enter().append('div').attr('class', 'restriction-control restriction-via-way');
81620 viaControlEnter.append('span').attr('class', 'restriction-control-label restriction-via-way-label').html(_t.html('restriction.controls.via') + ':');
81621 viaControlEnter.append('input').attr('class', 'restriction-via-way-input').attr('type', 'range').attr('min', '0').attr('max', '2').attr('step', '1');
81622 viaControlEnter.append('span').attr('class', 'restriction-via-way-text'); // update
81624 selection.selectAll('.restriction-via-way-input').property('value', _maxViaWay).on('input', function () {
81625 var val = select(this).property('value');
81628 _container.selectAll('.layer-osm .layer-turns *').remove();
81630 corePreferences('turn-restriction-via-way0', _maxViaWay);
81632 _parent.call(restrictions);
81634 selection.selectAll('.restriction-via-way-text').html(displayMaxVia(_maxViaWay));
81637 function renderViewer(selection) {
81638 if (!_intersection) return;
81639 var vgraph = _intersection.graph;
81640 var filter = utilFunctor(true);
81641 var projection = geoRawMercator(); // Reflow warning: `utilGetDimensions` calls `getBoundingClientRect`
81642 // Instead of asking the restriction-container for its dimensions,
81643 // we can ask the .sidebar, which can have its dimensions cached.
81644 // width: calc as sidebar - padding
81645 // height: hardcoded (from `80_app.css`)
81646 // var d = utilGetDimensions(selection);
81648 var sdims = utilGetDimensions(context.container().select('.sidebar'));
81649 var d = [sdims[0] - 50, 370];
81650 var c = geoVecScale(d, 0.5);
81652 projection.scale(geoZoomToScale(z)); // Calculate extent of all key vertices
81654 var extent = geoExtent();
81656 for (var i = 0; i < _intersection.vertices.length; i++) {
81657 extent._extend(_intersection.vertices[i].extent());
81658 } // If this is a large intersection, adjust zoom to fit extent
81661 if (_intersection.vertices.length > 1) {
81662 var padding = 180; // in z22 pixels
81664 var tl = projection([extent[0][0], extent[1][1]]);
81665 var br = projection([extent[1][0], extent[0][1]]);
81666 var hFactor = (br[0] - tl[0]) / (d[0] - padding);
81667 var vFactor = (br[1] - tl[1]) / (d[1] - padding);
81668 var hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2;
81669 var vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2;
81670 z = z - Math.max(hZoomDiff, vZoomDiff);
81671 projection.scale(geoZoomToScale(z));
81674 var padTop = 35; // reserve top space for hint text
81676 var extentCenter = projection(extent.center());
81677 extentCenter[1] = extentCenter[1] - padTop;
81678 projection.translate(geoVecSubtract(c, extentCenter)).clipExtent([[0, 0], d]);
81679 var drawLayers = svgLayers(projection, context).only(['osm', 'touch']).dimensions(d);
81680 var drawVertices = svgVertices(projection, context);
81681 var drawLines = svgLines(projection, context);
81682 var drawTurns = svgTurns(projection, context);
81683 var firstTime = selection.selectAll('.surface').empty();
81684 selection.call(drawLayers);
81685 var surface = selection.selectAll('.surface').classed('tr', true);
81688 _initialized = true;
81689 surface.call(breathe);
81690 } // This can happen if we've lowered the detail while a FROM way
81691 // is selected, and that way is no longer part of the intersection.
81694 if (_fromWayID && !vgraph.hasEntity(_fromWayID)) {
81699 surface.call(utilSetDimensions, d).call(drawVertices, vgraph, _intersection.vertices, filter, extent, z).call(drawLines, vgraph, _intersection.ways, filter).call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay));
81700 surface.on('click.restrictions', click).on('mouseover.restrictions', mouseover);
81701 surface.selectAll('.selected').classed('selected', false);
81702 surface.selectAll('.related').classed('related', false);
81706 way = vgraph.entity(_fromWayID);
81707 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
81710 document.addEventListener('resizeWindow', function () {
81711 utilSetDimensions(_container, null);
81716 function click(d3_event) {
81717 surface.call(breathe.off).call(breathe);
81718 var datum = d3_event.target.__data__;
81719 var entity = datum && datum.properties && datum.properties.entity;
81725 if (datum instanceof osmWay && (datum.__from || datum.__via)) {
81726 _fromWayID = datum.id;
81729 } else if (datum instanceof osmTurn) {
81730 var actions, extraActions, turns, i;
81731 var restrictionType = osmInferRestriction(vgraph, datum, projection);
81733 if (datum.restrictionID && !datum.direct) {
81735 } else if (datum.restrictionID && !datum.only) {
81738 var datumOnly = JSON.parse(JSON.stringify(datum)); // deep clone the datum
81740 datumOnly.only = true; // but change this property
81742 restrictionType = restrictionType.replace(/^no/, 'only'); // Adding an ONLY restriction should destroy all other direct restrictions from the FROM towards the VIA.
81743 // We will remember them in _oldTurns, and restore them if the user clicks again.
81745 turns = _intersection.turns(_fromWayID, 2);
81749 for (i = 0; i < turns.length; i++) {
81750 var turn = turns[i];
81751 if (seen[turn.restrictionID]) continue; // avoid deleting the turn twice (#4968, #4928)
81753 if (turn.direct && turn.path[1] === datum.path[1]) {
81754 seen[turns[i].restrictionID] = true;
81755 turn.restrictionType = osmInferRestriction(vgraph, turn, projection);
81757 _oldTurns.push(turn);
81759 extraActions.push(actionUnrestrictTurn(turn));
81763 actions = _intersection.actions.concat(extraActions, [actionRestrictTurn(datumOnly, restrictionType), _t('operations.restriction.annotation.create')]);
81764 } else if (datum.restrictionID) {
81766 // Restore whatever restrictions we might have destroyed by cycling thru the ONLY state.
81767 // This relies on the assumption that the intersection was already split up when we
81768 // performed the previous action (NO -> ONLY), so the IDs in _oldTurns shouldn't have changed.
81769 turns = _oldTurns || [];
81772 for (i = 0; i < turns.length; i++) {
81773 if (turns[i].key !== datum.key) {
81774 extraActions.push(actionRestrictTurn(turns[i], turns[i].restrictionType));
81779 actions = _intersection.actions.concat(extraActions, [actionUnrestrictTurn(datum), _t('operations.restriction.annotation.delete')]);
81782 actions = _intersection.actions.concat([actionRestrictTurn(datum, restrictionType), _t('operations.restriction.annotation.create')]);
81785 context.perform.apply(context, actions); // At this point the datum will be changed, but will have same key..
81786 // Refresh it and update the help..
81788 var s = surface.selectAll('.' + datum.key);
81789 datum = s.empty() ? null : s.datum();
81790 updateHints(datum);
81798 function mouseover(d3_event) {
81799 var datum = d3_event.target.__data__;
81800 updateHints(datum);
81803 _lastXPos = _lastXPos || sdims[0];
81805 function redraw(minChange) {
81809 xPos = utilGetDimensions(context.container().select('.sidebar'))[0];
81812 if (!minChange || minChange && Math.abs(xPos - _lastXPos) >= minChange) {
81813 if (context.hasEntity(_vertexID)) {
81816 _container.call(renderViewer);
81821 function highlightPathsFrom(wayID) {
81822 surface.selectAll('.related').classed('related', false).classed('allow', false).classed('restrict', false).classed('only', false);
81823 surface.selectAll('.' + wayID).classed('related', true);
81826 var turns = _intersection.turns(wayID, _maxViaWay);
81828 for (var i = 0; i < turns.length; i++) {
81829 var turn = turns[i];
81830 var ids = [turn.to.way];
81831 var klass = turn.no ? 'restrict' : turn.only ? 'only' : 'allow';
81833 if (turn.only || turns.length === 1) {
81834 if (turn.via.ways) {
81835 ids = ids.concat(turn.via.ways);
81837 } else if (turn.to.way === wayID) {
81841 surface.selectAll(utilEntitySelector(ids)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only');
81846 function updateHints(datum) {
81847 var help = _container.selectAll('.restriction-help').html('');
81849 var placeholders = {};
81850 ['from', 'via', 'to'].forEach(function (k) {
81851 placeholders[k] = '<span class="qualifier">' + _t('restriction.help.' + k) + '</span>';
81853 var entity = datum && datum.properties && datum.properties.entity;
81860 way = vgraph.entity(_fromWayID);
81861 surface.selectAll('.' + _fromWayID).classed('selected', true).classed('related', true);
81862 } // Hovering a way
81865 if (datum instanceof osmWay && datum.__from) {
81867 highlightPathsFrom(_fromWayID ? null : way.id);
81868 surface.selectAll('.' + way.id).classed('related', true);
81869 var clickSelect = !_fromWayID || _fromWayID !== way.id;
81870 help.append('div') // "Click to select FROM {fromName}." / "FROM {fromName}"
81871 .html(_t.html('restriction.help.' + (clickSelect ? 'select_from_name' : 'from_name'), {
81872 from: placeholders.from,
81873 fromName: displayName(way.id, vgraph)
81874 })); // Hovering a turn arrow
81875 } else if (datum instanceof osmTurn) {
81876 var restrictionType = osmInferRestriction(vgraph, datum, projection);
81877 var turnType = restrictionType.replace(/^(only|no)\_/, '');
81878 var indirect = datum.direct === false ? _t.html('restriction.help.indirect') : '';
81879 var klass, turnText, nextText;
81882 klass = 'restrict';
81883 turnText = _t.html('restriction.help.turn.no_' + turnType, {
81886 nextText = _t.html('restriction.help.turn.only_' + turnType, {
81889 } else if (datum.only) {
81891 turnText = _t.html('restriction.help.turn.only_' + turnType, {
81894 nextText = _t.html('restriction.help.turn.allowed_' + turnType, {
81899 turnText = _t.html('restriction.help.turn.allowed_' + turnType, {
81902 nextText = _t.html('restriction.help.turn.no_' + turnType, {
81907 help.append('div') // "NO Right Turn (indirect)"
81908 .attr('class', 'qualifier ' + klass).html(turnText);
81909 help.append('div') // "FROM {fromName} TO {toName}"
81910 .html(_t.html('restriction.help.from_name_to_name', {
81911 from: placeholders.from,
81912 fromName: displayName(datum.from.way, vgraph),
81913 to: placeholders.to,
81914 toName: displayName(datum.to.way, vgraph)
81917 if (datum.via.ways && datum.via.ways.length) {
81920 for (var i = 0; i < datum.via.ways.length; i++) {
81921 var prev = names[names.length - 1];
81922 var curr = displayName(datum.via.ways[i], vgraph);
81924 if (!prev || curr !== prev) {
81925 // collapse identical names
81930 help.append('div') // "VIA {viaNames}"
81931 .html(_t.html('restriction.help.via_names', {
81932 via: placeholders.via,
81933 viaNames: names.join(', ')
81938 help.append('div') // Click for "No Right Turn"
81939 .html(_t.html('restriction.help.toggle', {
81940 turn: nextText.trim()
81944 highlightPathsFrom(null);
81945 var alongIDs = datum.path.slice();
81946 surface.selectAll(utilEntitySelector(alongIDs)).classed('related', true).classed('allow', klass === 'allow').classed('restrict', klass === 'restrict').classed('only', klass === 'only'); // Hovering empty surface
81948 highlightPathsFrom(null);
81951 help.append('div') // "FROM {fromName}"
81952 .html(_t.html('restriction.help.from_name', {
81953 from: placeholders.from,
81954 fromName: displayName(_fromWayID, vgraph)
81957 help.append('div') // "Click to select a FROM segment."
81958 .html(_t.html('restriction.help.select_from', {
81959 from: placeholders.from
81966 function displayMaxDistance(maxDist) {
81967 var isImperial = !_mainLocalizer.usesMetric();
81972 // imprecise conversion for prettier display
81982 distance: _t('units.feet', {
81983 quantity: distToFeet
81988 distance: _t('units.meters', {
81994 return _t.html('restriction.controls.distance_up_to', opts);
81997 function displayMaxVia(maxVia) {
81998 return maxVia === 0 ? _t.html('restriction.controls.via_node_only') : maxVia === 1 ? _t.html('restriction.controls.via_up_to_one') : _t.html('restriction.controls.via_up_to_two');
82001 function displayName(entityID, graph) {
82002 var entity = graph.entity(entityID);
82003 var name = utilDisplayName(entity) || '';
82004 var matched = _mainPresetIndex.match(entity, graph);
82005 var type = matched && matched.name() || utilDisplayType(entity.id);
82006 return name || type;
82009 restrictions.entityIDs = function (val) {
82010 _intersection = null;
82013 _vertexID = val[0];
82016 restrictions.tags = function () {};
82018 restrictions.focus = function () {};
82020 restrictions.off = function (selection) {
82021 if (!_initialized) return;
82022 selection.selectAll('.surface').call(breathe.off).on('click.restrictions', null).on('mouseover.restrictions', null);
82023 select(window).on('resize.restrictions', null);
82026 return utilRebind(restrictions, dispatch, 'on');
82028 uiFieldRestrictions.supportsMultiselection = false;
82030 function uiFieldTextarea(field, context) {
82031 var dispatch = dispatch$8('change');
82032 var input = select(null);
82036 function textarea(selection) {
82037 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82038 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82039 input = wrap.selectAll('textarea').data([0]);
82040 input = input.enter().append('textarea').attr('id', field.domId).call(utilNoAuto).on('input', change(true)).on('blur', change()).on('change', change()).merge(input);
82043 function change(onInput) {
82044 return function () {
82045 var val = utilGetSetValue(input);
82046 if (!onInput) val = context.cleanTagValue(val); // don't override multiple values with blank string
82048 if (!val && Array.isArray(_tags[field.key])) return;
82050 t[field.key] = val || undefined;
82051 dispatch.call('change', this, t, onInput);
82055 textarea.tags = function (tags) {
82057 var isMixed = Array.isArray(tags[field.key]);
82058 utilGetSetValue(input, !isMixed && tags[field.key] ? tags[field.key] : '').attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : undefined).attr('placeholder', isMixed ? _t('inspector.multiple_values') : field.placeholder() || _t('inspector.unknown')).classed('mixed', isMixed);
82061 textarea.focus = function () {
82062 input.node().focus();
82065 return utilRebind(textarea, dispatch, 'on');
82069 var getOwnPropertyDescriptor = objectGetOwnPropertyDescriptor.f;
82070 var toLength = toLength$q;
82071 var notARegExp = notARegexp;
82072 var requireObjectCoercible = requireObjectCoercible$e;
82073 var correctIsRegExpLogic = correctIsRegexpLogic;
82075 // eslint-disable-next-line es/no-string-prototype-endswith -- safe
82076 var $endsWith = ''.endsWith;
82077 var min = Math.min;
82079 var CORRECT_IS_REGEXP_LOGIC = correctIsRegExpLogic('endsWith');
82080 // https://github.com/zloirock/core-js/pull/702
82081 var MDN_POLYFILL_BUG = !CORRECT_IS_REGEXP_LOGIC && !!function () {
82082 var descriptor = getOwnPropertyDescriptor(String.prototype, 'endsWith');
82083 return descriptor && !descriptor.writable;
82086 // `String.prototype.endsWith` method
82087 // https://tc39.es/ecma262/#sec-string.prototype.endswith
82088 $({ target: 'String', proto: true, forced: !MDN_POLYFILL_BUG && !CORRECT_IS_REGEXP_LOGIC }, {
82089 endsWith: function endsWith(searchString /* , endPosition = @length */) {
82090 var that = String(requireObjectCoercible(this));
82091 notARegExp(searchString);
82092 var endPosition = arguments.length > 1 ? arguments[1] : undefined;
82093 var len = toLength(that.length);
82094 var end = endPosition === undefined ? len : min(toLength(endPosition), len);
82095 var search = String(searchString);
82097 ? $endsWith.call(that, search, end)
82098 : that.slice(end - search.length, end) === search;
82102 function uiFieldWikidata(field, context) {
82103 var wikidata = services.wikidata;
82104 var dispatch = dispatch$8('change');
82106 var _selection = select(null);
82108 var _searchInput = select(null);
82111 var _wikidataEntity = null;
82113 var _entityIDs = [];
82115 var _wikipediaKey = field.keys && field.keys.find(function (key) {
82116 return key.includes('wikipedia');
82118 _hintKey = field.key === 'wikidata' ? 'name' : field.key.split(':')[0];
82120 var combobox = uiCombobox(context, 'combo-' + field.safeid).caseSensitive(true).minItems(1);
82122 function wiki(selection) {
82123 _selection = selection;
82124 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82125 wrap = wrap.enter().append('div').attr('class', 'form-field-input-wrap form-field-input-' + field.type).merge(wrap);
82126 var list = wrap.selectAll('ul').data([0]);
82127 list = list.enter().append('ul').attr('class', 'rows').merge(list);
82128 var searchRow = list.selectAll('li.wikidata-search').data([0]);
82129 var searchRowEnter = searchRow.enter().append('li').attr('class', 'wikidata-search');
82130 searchRowEnter.append('input').attr('type', 'text').attr('id', field.domId).style('flex', '1').call(utilNoAuto).on('focus', function () {
82131 var node = select(this).node();
82132 node.setSelectionRange(0, node.value.length);
82133 }).on('blur', function () {
82134 setLabelForEntity();
82135 }).call(combobox.fetcher(fetchWikidataItems));
82136 combobox.on('accept', function (d) {
82141 }).on('cancel', function () {
82142 setLabelForEntity();
82144 searchRowEnter.append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
82145 domain: 'wikidata.org'
82146 })).call(svgIcon('#iD-icon-out-link')).on('click', function (d3_event) {
82147 d3_event.preventDefault();
82148 if (_wikiURL) window.open(_wikiURL, '_blank');
82150 searchRow = searchRow.merge(searchRowEnter);
82151 _searchInput = searchRow.select('input');
82152 var wikidataProperties = ['description', 'identifier'];
82153 var items = list.selectAll('li.labeled-input').data(wikidataProperties); // Enter
82155 var enter = items.enter().append('li').attr('class', function (d) {
82156 return 'labeled-input preset-wikidata-' + d;
82158 enter.append('span').attr('class', 'label').html(function (d) {
82159 return _t.html('wikidata.' + d);
82161 enter.append('input').attr('type', 'text').call(utilNoAuto).classed('disabled', 'true').attr('readonly', 'true');
82162 enter.append('button').attr('class', 'form-field-button').attr('title', _t('icons.copy')).call(svgIcon('#iD-operation-copy')).on('click', function (d3_event) {
82163 d3_event.preventDefault();
82164 select(this.parentNode).select('input').node().select();
82165 document.execCommand('copy');
82169 function fetchWikidataItems(q, callback) {
82170 if (!q && _hintKey) {
82171 // other tags may be good search terms
82172 for (var i in _entityIDs) {
82173 var entity = context.hasEntity(_entityIDs[i]);
82175 if (entity.tags[_hintKey]) {
82176 q = entity.tags[_hintKey];
82182 wikidata.itemsForSearchQuery(q, function (err, data) {
82185 for (var i in data) {
82186 data[i].value = data[i].label + ' (' + data[i].id + ')';
82187 data[i].title = data[i].description;
82190 if (callback) callback(data);
82194 function change() {
82196 syncTags[field.key] = _qid;
82197 dispatch.call('change', this, syncTags); // attempt asynchronous update of wikidata tag..
82199 var initGraph = context.graph();
82200 var initEntityIDs = _entityIDs;
82201 wikidata.entityByQID(_qid, function (err, entity) {
82202 if (err) return; // If graph has changed, we can't apply this update.
82204 if (context.graph() !== initGraph) return;
82205 if (!entity.sitelinks) return;
82206 var langs = wikidata.languagesToQuery(); // use the label and description languages as fallbacks
82208 ['labels', 'descriptions'].forEach(function (key) {
82209 if (!entity[key]) return;
82210 var valueLangs = Object.keys(entity[key]);
82211 if (valueLangs.length === 0) return;
82212 var valueLang = valueLangs[0];
82214 if (langs.indexOf(valueLang) === -1) {
82215 langs.push(valueLang);
82218 var newWikipediaValue;
82220 if (_wikipediaKey) {
82221 var foundPreferred;
82223 for (var i in langs) {
82224 var lang = langs[i];
82225 var siteID = lang.replace('-', '_') + 'wiki';
82227 if (entity.sitelinks[siteID]) {
82228 foundPreferred = true;
82229 newWikipediaValue = lang + ':' + entity.sitelinks[siteID].title; // use the first match
82235 if (!foundPreferred) {
82236 // No wikipedia sites available in the user's language or the fallback languages,
82237 // default to any wikipedia sitelink
82238 var wikiSiteKeys = Object.keys(entity.sitelinks).filter(function (site) {
82239 return site.endsWith('wiki');
82242 if (wikiSiteKeys.length === 0) {
82243 // if no wikipedia pages are linked to this wikidata entity, delete that tag
82244 newWikipediaValue = null;
82246 var wikiLang = wikiSiteKeys[0].slice(0, -4).replace('_', '-');
82247 var wikiTitle = entity.sitelinks[wikiSiteKeys[0]].title;
82248 newWikipediaValue = wikiLang + ':' + wikiTitle;
82253 if (newWikipediaValue) {
82254 newWikipediaValue = context.cleanTagValue(newWikipediaValue);
82257 if (typeof newWikipediaValue === 'undefined') return;
82258 var actions = initEntityIDs.map(function (entityID) {
82259 var entity = context.hasEntity(entityID);
82260 if (!entity) return null;
82261 var currTags = Object.assign({}, entity.tags); // shallow copy
82263 if (newWikipediaValue === null) {
82264 if (!currTags[_wikipediaKey]) return null;
82265 delete currTags[_wikipediaKey];
82267 currTags[_wikipediaKey] = newWikipediaValue;
82270 return actionChangeTags(entityID, currTags);
82271 }).filter(Boolean);
82272 if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
82274 context.overwrite(function actionUpdateWikipediaTags(graph) {
82275 actions.forEach(function (action) {
82276 graph = action(graph);
82279 }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
82280 // changeTags() is not intended to be called asynchronously
82284 function setLabelForEntity() {
82287 if (_wikidataEntity) {
82288 label = entityPropertyForDisplay(_wikidataEntity, 'labels');
82290 if (label.length === 0) {
82291 label = _wikidataEntity.id.toString();
82295 utilGetSetValue(_searchInput, label);
82298 wiki.tags = function (tags) {
82299 var isMixed = Array.isArray(tags[field.key]);
82301 _searchInput.attr('title', isMixed ? tags[field.key].filter(Boolean).join('\n') : null).attr('placeholder', isMixed ? _t('inspector.multiple_values') : '').classed('mixed', isMixed);
82303 _qid = typeof tags[field.key] === 'string' && tags[field.key] || '';
82305 if (!/^Q[0-9]*$/.test(_qid)) {
82306 // not a proper QID
82309 } // QID value in correct format
82312 _wikiURL = 'https://wikidata.org/wiki/' + _qid;
82313 wikidata.entityByQID(_qid, function (err, entity) {
82319 _wikidataEntity = entity;
82320 setLabelForEntity();
82321 var description = entityPropertyForDisplay(entity, 'descriptions');
82323 _selection.select('button.wiki-link').classed('disabled', false);
82325 _selection.select('.preset-wikidata-description').style('display', function () {
82326 return description.length > 0 ? 'flex' : 'none';
82327 }).select('input').attr('value', description);
82329 _selection.select('.preset-wikidata-identifier').style('display', function () {
82330 return entity.id ? 'flex' : 'none';
82331 }).select('input').attr('value', entity.id);
82332 }); // not a proper QID
82334 function unrecognized() {
82335 _wikidataEntity = null;
82336 setLabelForEntity();
82338 _selection.select('.preset-wikidata-description').style('display', 'none');
82340 _selection.select('.preset-wikidata-identifier').style('display', 'none');
82342 _selection.select('button.wiki-link').classed('disabled', true);
82344 if (_qid && _qid !== '') {
82345 _wikiURL = 'https://wikidata.org/wiki/Special:Search?search=' + _qid;
82352 function entityPropertyForDisplay(wikidataEntity, propKey) {
82353 if (!wikidataEntity[propKey]) return '';
82354 var propObj = wikidataEntity[propKey];
82355 var langKeys = Object.keys(propObj);
82356 if (langKeys.length === 0) return ''; // sorted by priority, since we want to show the user's language first if possible
82358 var langs = wikidata.languagesToQuery();
82360 for (var i in langs) {
82361 var lang = langs[i];
82362 var valueObj = propObj[lang];
82363 if (valueObj && valueObj.value && valueObj.value.length > 0) return valueObj.value;
82364 } // default to any available value
82367 return propObj[langKeys[0]].value;
82370 wiki.entityIDs = function (val) {
82371 if (!arguments.length) return _entityIDs;
82376 wiki.focus = function () {
82377 _searchInput.node().focus();
82380 return utilRebind(wiki, dispatch, 'on');
82383 function uiFieldWikipedia(field, context) {
82384 var _arguments = arguments;
82385 var dispatch = dispatch$8('change');
82386 var wikipedia = services.wikipedia;
82387 var wikidata = services.wikidata;
82389 var _langInput = select(null);
82391 var _titleInput = select(null);
82399 var _dataWikipedia = [];
82400 _mainFileFetcher.get('wmf_sitematrix').then(function (d) {
82401 _dataWikipedia = d;
82402 if (_tags) updateForTags(_tags);
82403 })["catch"](function () {
82406 var langCombo = uiCombobox(context, 'wikipedia-lang').fetcher(function (value, callback) {
82407 var v = value.toLowerCase();
82408 callback(_dataWikipedia.filter(function (d) {
82409 return d[0].toLowerCase().indexOf(v) >= 0 || d[1].toLowerCase().indexOf(v) >= 0 || d[2].toLowerCase().indexOf(v) >= 0;
82410 }).map(function (d) {
82416 var titleCombo = uiCombobox(context, 'wikipedia-title').fetcher(function (value, callback) {
82420 for (var i in _entityIDs) {
82421 var entity = context.hasEntity(_entityIDs[i]);
82423 if (entity.tags.name) {
82424 value = entity.tags.name;
82430 var searchfn = value.length > 7 ? wikipedia.search : wikipedia.suggestions;
82431 searchfn(language()[2], value, function (query, data) {
82432 callback(data.map(function (d) {
82440 function wiki(selection) {
82441 var wrap = selection.selectAll('.form-field-input-wrap').data([0]);
82442 wrap = wrap.enter().append('div').attr('class', "form-field-input-wrap form-field-input-".concat(field.type)).merge(wrap);
82443 var langContainer = wrap.selectAll('.wiki-lang-container').data([0]);
82444 langContainer = langContainer.enter().append('div').attr('class', 'wiki-lang-container').merge(langContainer);
82445 _langInput = langContainer.selectAll('input.wiki-lang').data([0]);
82446 _langInput = _langInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-lang').attr('placeholder', _t('translate.localized_translation_language')).call(utilNoAuto).call(langCombo).merge(_langInput);
82448 _langInput.on('blur', changeLang).on('change', changeLang);
82450 var titleContainer = wrap.selectAll('.wiki-title-container').data([0]);
82451 titleContainer = titleContainer.enter().append('div').attr('class', 'wiki-title-container').merge(titleContainer);
82452 _titleInput = titleContainer.selectAll('input.wiki-title').data([0]);
82453 _titleInput = _titleInput.enter().append('input').attr('type', 'text').attr('class', 'wiki-title').attr('id', field.domId).call(utilNoAuto).call(titleCombo).merge(_titleInput);
82455 _titleInput.on('blur', function () {
82457 }).on('change', function () {
82461 var link = titleContainer.selectAll('.wiki-link').data([0]);
82462 link = link.enter().append('button').attr('class', 'form-field-button wiki-link').attr('title', _t('icons.view_on', {
82463 domain: 'wikipedia.org'
82464 })).call(svgIcon('#iD-icon-out-link')).merge(link);
82465 link.on('click', function (d3_event) {
82466 d3_event.preventDefault();
82467 if (_wikiURL) window.open(_wikiURL, '_blank');
82471 function defaultLanguageInfo(skipEnglishFallback) {
82472 var langCode = _mainLocalizer.languageCode().toLowerCase();
82474 for (var i in _dataWikipedia) {
82475 var d = _dataWikipedia[i]; // default to the language of iD's current locale
82477 if (d[2] === langCode) return d;
82478 } // fallback to English
82481 return skipEnglishFallback ? ['', '', ''] : ['English', 'English', 'en'];
82484 function language(skipEnglishFallback) {
82485 var value = utilGetSetValue(_langInput).toLowerCase();
82487 for (var i in _dataWikipedia) {
82488 var d = _dataWikipedia[i]; // return the language already set in the UI, if supported
82490 if (d[0].toLowerCase() === value || d[1].toLowerCase() === value || d[2] === value) return d;
82491 } // fallback to English
82494 return defaultLanguageInfo(skipEnglishFallback);
82497 function changeLang() {
82498 utilGetSetValue(_langInput, language()[1]);
82502 function change(skipWikidata) {
82503 var value = utilGetSetValue(_titleInput);
82504 var m = value.match(/https?:\/\/([-a-z]+)\.wikipedia\.org\/(?:wiki|\1-[-a-z]+)\/([^#]+)(?:#(.+))?/);
82506 var langInfo = m && _dataWikipedia.find(function (d) {
82507 return m[1] === d[2];
82513 var nativeLangName = langInfo[1]; // Normalize title http://www.mediawiki.org/wiki/API:Query#Title_normalization
82515 value = decodeURIComponent(m[2]).replace(/_/g, ' ');
82518 var anchor; // try {
82519 // leave this out for now - #6232
82520 // Best-effort `anchordecode:` implementation
82521 // anchor = decodeURIComponent(m[3].replace(/\.([0-9A-F]{2})/g, '%$1'));
82524 anchor = decodeURIComponent(m[3]); // }
82526 value += '#' + anchor.replace(/_/g, ' ');
82529 value = value.slice(0, 1).toUpperCase() + value.slice(1);
82530 utilGetSetValue(_langInput, nativeLangName);
82531 utilGetSetValue(_titleInput, value);
82535 syncTags.wikipedia = context.cleanTagValue(language()[2] + ':' + value);
82537 syncTags.wikipedia = undefined;
82540 dispatch.call('change', this, syncTags);
82541 if (skipWikidata || !value || !language()[2]) return; // attempt asynchronous update of wikidata tag..
82543 var initGraph = context.graph();
82544 var initEntityIDs = _entityIDs;
82545 wikidata.itemsByTitle(language()[2], value, function (err, data) {
82546 if (err || !data || !Object.keys(data).length) return; // If graph has changed, we can't apply this update.
82548 if (context.graph() !== initGraph) return;
82549 var qids = Object.keys(data);
82550 var value = qids && qids.find(function (id) {
82551 return id.match(/^Q\d+$/);
82553 var actions = initEntityIDs.map(function (entityID) {
82554 var entity = context.entity(entityID).tags;
82555 var currTags = Object.assign({}, entity); // shallow copy
82557 if (currTags.wikidata !== value) {
82558 currTags.wikidata = value;
82559 return actionChangeTags(entityID, currTags);
82563 }).filter(Boolean);
82564 if (!actions.length) return; // Coalesce the update of wikidata tag into the previous tag change
82566 context.overwrite(function actionUpdateWikidataTags(graph) {
82567 actions.forEach(function (action) {
82568 graph = action(graph);
82571 }, context.history().undoAnnotation()); // do not dispatch.call('change') here, because entity_editor
82572 // changeTags() is not intended to be called asynchronously
82576 wiki.tags = function (tags) {
82578 updateForTags(tags);
82581 function updateForTags(tags) {
82582 var value = typeof tags[field.key] === 'string' ? tags[field.key] : ''; // Expect tag format of `tagLang:tagArticleTitle`, e.g. `fr:Paris`, with
82583 // optional suffix of `#anchor`
82585 var m = value.match(/([^:]+):([^#]+)(?:#(.+))?/);
82586 var tagLang = m && m[1];
82587 var tagArticleTitle = m && m[2];
82588 var anchor = m && m[3];
82590 var tagLangInfo = tagLang && _dataWikipedia.find(function (d) {
82591 return tagLang === d[2];
82592 }); // value in correct format
82596 var nativeLangName = tagLangInfo[1];
82597 utilGetSetValue(_langInput, nativeLangName);
82598 utilGetSetValue(_titleInput, tagArticleTitle + (anchor ? '#' + anchor : ''));
82602 // Best-effort `anchorencode:` implementation
82603 anchor = encodeURIComponent(anchor.replace(/ /g, '_')).replace(/%/g, '.');
82605 anchor = anchor.replace(/ /g, '_');
82609 _wikiURL = 'https://' + tagLang + '.wikipedia.org/wiki/' + tagArticleTitle.replace(/ /g, '_') + (anchor ? '#' + anchor : ''); // unrecognized value format
82611 utilGetSetValue(_titleInput, value);
82613 if (value && value !== '') {
82614 utilGetSetValue(_langInput, '');
82615 var defaultLangInfo = defaultLanguageInfo();
82616 _wikiURL = "https://".concat(defaultLangInfo[2], ".wikipedia.org/w/index.php?fulltext=1&search=").concat(value);
82618 var shownOrDefaultLangInfo = language(true
82619 /* skipEnglishFallback */
82621 utilGetSetValue(_langInput, shownOrDefaultLangInfo[1]);
82627 wiki.entityIDs = function (val) {
82628 if (!_arguments.length) return _entityIDs;
82633 wiki.focus = function () {
82634 _titleInput.node().focus();
82637 return utilRebind(wiki, dispatch, 'on');
82639 uiFieldWikipedia.supportsMultiselection = false;
82642 access: uiFieldAccess,
82643 address: uiFieldAddress,
82644 check: uiFieldCheck,
82645 combo: uiFieldCombo,
82646 cycleway: uiFieldCycleway,
82647 defaultCheck: uiFieldCheck,
82648 email: uiFieldText,
82649 identifier: uiFieldText,
82650 lanes: uiFieldLanes,
82651 localized: uiFieldLocalized,
82652 roadheight: uiFieldRoadheight,
82653 roadspeed: uiFieldRoadspeed,
82654 manyCombo: uiFieldCombo,
82655 multiCombo: uiFieldCombo,
82656 networkCombo: uiFieldCombo,
82657 number: uiFieldText,
82658 onewayCheck: uiFieldCheck,
82659 radio: uiFieldRadio,
82660 restrictions: uiFieldRestrictions,
82661 semiCombo: uiFieldCombo,
82662 structureRadio: uiFieldRadio,
82665 textarea: uiFieldTextarea,
82666 typeCombo: uiFieldCombo,
82668 wikidata: uiFieldWikidata,
82669 wikipedia: uiFieldWikipedia
82672 function uiField(context, presetField, entityIDs, options) {
82673 options = Object.assign({
82680 var dispatch = dispatch$8('change', 'revert');
82681 var field = Object.assign({}, presetField); // shallow copy
82683 field.domId = utilUniqueDomId('form-field-' + field.safeid);
82684 var _show = options.show;
82690 if (entityIDs && entityIDs.length) {
82691 _entityExtent = entityIDs.reduce(function (extent, entityID) {
82692 var entity = context.graph().entity(entityID);
82693 return extent.extend(entity.extent(context.graph()));
82697 var _locked = false;
82699 var _lockedTip = uiTooltip().title(_t.html('inspector.lock.suggestion', {
82701 })).placement('bottom');
82703 field.keys = field.keys || [field.key]; // only create the fields that are actually being shown
82705 if (_show && !field.impl) {
82707 } // Creates the field.. This is done lazily,
82708 // once we know that the field will be shown.
82711 function createField() {
82712 field.impl = uiFields[field.type](field, context).on('change', function (t, onInput) {
82713 dispatch.call('change', field, t, onInput);
82717 field.entityIDs = entityIDs; // if this field cares about the entities, pass them along
82719 if (field.impl.entityIDs) {
82720 field.impl.entityIDs(entityIDs);
82725 function isModified() {
82726 if (!entityIDs || !entityIDs.length) return false;
82727 return entityIDs.some(function (entityID) {
82728 var original = context.graph().base().entities[entityID];
82729 var latest = context.graph().entity(entityID);
82730 return field.keys.some(function (key) {
82731 return original ? latest.tags[key] !== original.tags[key] : latest.tags[key];
82736 function tagsContainFieldKey() {
82737 return field.keys.some(function (key) {
82738 if (field.type === 'multiCombo') {
82739 for (var tagKey in _tags) {
82740 if (tagKey.indexOf(key) === 0) {
82748 return _tags[key] !== undefined;
82752 function revert(d3_event, d) {
82753 d3_event.stopPropagation();
82754 d3_event.preventDefault();
82755 if (!entityIDs || _locked) return;
82756 dispatch.call('revert', d, d.keys);
82759 function remove(d3_event, d) {
82760 d3_event.stopPropagation();
82761 d3_event.preventDefault();
82762 if (_locked) return;
82764 d.keys.forEach(function (key) {
82765 t[key] = undefined;
82767 dispatch.call('change', d, t);
82770 field.render = function (selection) {
82771 var container = selection.selectAll('.form-field').data([field]); // Enter
82773 var enter = container.enter().append('div').attr('class', function (d) {
82774 return 'form-field form-field-' + d.safeid;
82775 }).classed('nowrap', !options.wrap);
82777 if (options.wrap) {
82778 var labelEnter = enter.append('label').attr('class', 'field-label').attr('for', function (d) {
82781 var textEnter = labelEnter.append('span').attr('class', 'label-text');
82782 textEnter.append('span').attr('class', 'label-textvalue').html(function (d) {
82785 textEnter.append('span').attr('class', 'label-textannotation');
82787 if (options.remove) {
82788 labelEnter.append('button').attr('class', 'remove-icon').attr('title', _t('icons.remove')).call(svgIcon('#iD-operation-delete'));
82791 if (options.revert) {
82792 labelEnter.append('button').attr('class', 'modified-icon').attr('title', _t('icons.undo')).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-redo' : '#iD-icon-undo'));
82797 container = container.merge(enter);
82798 container.select('.field-label > .remove-icon') // propagate bound data
82799 .on('click', remove);
82800 container.select('.field-label > .modified-icon') // propagate bound data
82801 .on('click', revert);
82802 container.each(function (d) {
82803 var selection = select(this);
82809 var reference, help; // instantiate field help
82811 if (options.wrap && field.type === 'restrictions') {
82812 help = uiFieldHelp(context, 'restrictions');
82813 } // instantiate tag reference
82816 if (options.wrap && options.info) {
82817 var referenceKey = d.key || '';
82819 if (d.type === 'multiCombo') {
82820 // lookup key without the trailing ':'
82821 referenceKey = referenceKey.replace(/:$/, '');
82824 reference = uiTagReference(d.reference || {
82828 if (_state === 'hover') {
82829 reference.showing(false);
82833 selection.call(d.impl); // add field help components
82836 selection.call(help.body).select('.field-label').call(help.button);
82837 } // add tag reference components
82841 selection.call(reference.body).select('.field-label').call(reference.button);
82844 d.impl.tags(_tags);
82846 container.classed('locked', _locked).classed('modified', isModified()).classed('present', tagsContainFieldKey()); // show a tip and lock icon if the field is locked
82848 var annotation = container.selectAll('.field-label .label-textannotation');
82849 var icon = annotation.selectAll('.icon').data(_locked ? [0] : []);
82850 icon.exit().remove();
82851 icon.enter().append('svg').attr('class', 'icon').append('use').attr('xlink:href', '#fas-lock');
82852 container.call(_locked ? _lockedTip : _lockedTip.destroy);
82855 field.state = function (val) {
82856 if (!arguments.length) return _state;
82861 field.tags = function (val) {
82862 if (!arguments.length) return _tags;
82865 if (tagsContainFieldKey() && !_show) {
82866 // always show a field if it has a value to display
82877 field.locked = function (val) {
82878 if (!arguments.length) return _locked;
82883 field.show = function () {
82890 if (field["default"] && field.key && _tags[field.key] !== field["default"]) {
82892 t[field.key] = field["default"];
82893 dispatch.call('change', this, t);
82895 }; // A shown field has a visible UI, a non-shown field is in the 'Add field' dropdown
82898 field.isShown = function () {
82900 }; // An allowed field can appear in the UI or in the 'Add field' dropdown.
82901 // A non-allowed field is hidden from the user altogether
82904 field.isAllowed = function () {
82905 if (entityIDs && entityIDs.length > 1 && uiFields[field.type].supportsMultiselection === false) return false;
82906 if (field.geometry && !entityIDs.every(function (entityID) {
82907 return field.matchGeometry(context.graph().geometry(entityID));
82910 if (entityIDs && _entityExtent && field.locationSetID) {
82911 // is field allowed in this location?
82912 var validLocations = _mainLocations.locationsAt(_entityExtent.center());
82913 if (!validLocations[field.locationSetID]) return false;
82916 var prerequisiteTag = field.prerequisiteTag;
82918 if (entityIDs && !tagsContainFieldKey() && // ignore tagging prerequisites if a value is already present
82920 if (!entityIDs.every(function (entityID) {
82921 var entity = context.graph().entity(entityID);
82923 if (prerequisiteTag.key) {
82924 var value = entity.tags[prerequisiteTag.key];
82925 if (!value) return false;
82927 if (prerequisiteTag.valueNot) {
82928 return prerequisiteTag.valueNot !== value;
82931 if (prerequisiteTag.value) {
82932 return prerequisiteTag.value === value;
82934 } else if (prerequisiteTag.keyNot) {
82935 if (entity.tags[prerequisiteTag.keyNot]) return false;
82945 field.focus = function () {
82947 field.impl.focus();
82951 return utilRebind(field, dispatch, 'on');
82954 function uiFormFields(context) {
82955 var moreCombo = uiCombobox(context, 'more-fields').minItems(1);
82956 var _fieldsArr = [];
82957 var _lastPlaceholder = '';
82961 function formFields(selection) {
82962 var allowedFields = _fieldsArr.filter(function (field) {
82963 return field.isAllowed();
82966 var shown = allowedFields.filter(function (field) {
82967 return field.isShown();
82969 var notShown = allowedFields.filter(function (field) {
82970 return !field.isShown();
82972 var container = selection.selectAll('.form-fields-container').data([0]);
82973 container = container.enter().append('div').attr('class', 'form-fields-container ' + (_klass || '')).merge(container);
82974 var fields = container.selectAll('.wrap-form-field').data(shown, function (d) {
82975 return d.id + (d.entityIDs ? d.entityIDs.join() : '');
82977 fields.exit().remove(); // Enter
82979 var enter = fields.enter().append('div').attr('class', function (d) {
82980 return 'wrap-form-field wrap-form-field-' + d.safeid;
82983 fields = fields.merge(enter);
82984 fields.order().each(function (d) {
82985 select(this).call(d.render);
82988 var moreFields = notShown.map(function (field) {
82989 var title = field.title();
82990 titles.push(title);
82991 var terms = field.terms();
82992 if (field.key) terms.push(field.key);
82993 if (field.keys) terms = terms.concat(field.keys);
82995 display: field.label(),
83002 var placeholder = titles.slice(0, 3).join(', ') + (titles.length > 3 ? '…' : '');
83003 var more = selection.selectAll('.more-fields').data(_state === 'hover' || moreFields.length === 0 ? [] : [0]);
83004 more.exit().remove();
83005 var moreEnter = more.enter().append('div').attr('class', 'more-fields').append('label');
83006 moreEnter.append('span').html(_t.html('inspector.add_fields'));
83007 more = moreEnter.merge(more);
83008 var input = more.selectAll('.value').data([0]);
83009 input.exit().remove();
83010 input = input.enter().append('input').attr('class', 'value').attr('type', 'text').attr('placeholder', placeholder).call(utilNoAuto).merge(input);
83011 input.call(utilGetSetValue, '').call(moreCombo.data(moreFields).on('accept', function (d) {
83012 if (!d) return; // user entered something that was not matched
83014 var field = d.field;
83016 selection.call(formFields); // rerender
83019 })); // avoid updating placeholder excessively (triggers style recalc)
83021 if (_lastPlaceholder !== placeholder) {
83022 input.attr('placeholder', placeholder);
83023 _lastPlaceholder = placeholder;
83027 formFields.fieldsArr = function (val) {
83028 if (!arguments.length) return _fieldsArr;
83029 _fieldsArr = val || [];
83033 formFields.state = function (val) {
83034 if (!arguments.length) return _state;
83039 formFields.klass = function (val) {
83040 if (!arguments.length) return _klass;
83048 function uiSectionPresetFields(context) {
83049 var section = uiSection('preset-fields', context).label(_t.html('inspector.fields')).disclosureContent(renderDisclosureContent);
83050 var dispatch = dispatch$8('change', 'revert');
83051 var formFields = uiFormFields(context);
83063 function renderDisclosureContent(selection) {
83065 var graph = context.graph();
83066 var geometries = Object.keys(_entityIDs.reduce(function (geoms, entityID) {
83067 geoms[graph.entity(entityID).geometry(graph)] = true;
83070 var presetsManager = _mainPresetIndex;
83071 var allFields = [];
83072 var allMoreFields = [];
83073 var sharedTotalFields;
83075 _presets.forEach(function (preset) {
83076 var fields = preset.fields();
83077 var moreFields = preset.moreFields();
83078 allFields = utilArrayUnion(allFields, fields);
83079 allMoreFields = utilArrayUnion(allMoreFields, moreFields);
83081 if (!sharedTotalFields) {
83082 sharedTotalFields = utilArrayUnion(fields, moreFields);
83084 sharedTotalFields = sharedTotalFields.filter(function (field) {
83085 return fields.indexOf(field) !== -1 || moreFields.indexOf(field) !== -1;
83090 var sharedFields = allFields.filter(function (field) {
83091 return sharedTotalFields.indexOf(field) !== -1;
83093 var sharedMoreFields = allMoreFields.filter(function (field) {
83094 return sharedTotalFields.indexOf(field) !== -1;
83097 sharedFields.forEach(function (field) {
83098 if (field.matchAllGeometry(geometries)) {
83099 _fieldsArr.push(uiField(context, field, _entityIDs));
83102 var singularEntity = _entityIDs.length === 1 && graph.hasEntity(_entityIDs[0]);
83104 if (singularEntity && singularEntity.isHighwayIntersection(graph) && presetsManager.field('restrictions')) {
83105 _fieldsArr.push(uiField(context, presetsManager.field('restrictions'), _entityIDs));
83108 var additionalFields = utilArrayUnion(sharedMoreFields, presetsManager.universal());
83109 additionalFields.sort(function (field1, field2) {
83110 return field1.label().localeCompare(field2.label(), _mainLocalizer.localeCode());
83112 additionalFields.forEach(function (field) {
83113 if (sharedFields.indexOf(field) === -1 && field.matchAllGeometry(geometries)) {
83114 _fieldsArr.push(uiField(context, field, _entityIDs, {
83120 _fieldsArr.forEach(function (field) {
83121 field.on('change', function (t, onInput) {
83122 dispatch.call('change', field, _entityIDs, t, onInput);
83123 }).on('revert', function (keys) {
83124 dispatch.call('revert', field, keys);
83129 _fieldsArr.forEach(function (field) {
83130 field.state(_state).tags(_tags);
83133 selection.call(formFields.fieldsArr(_fieldsArr).state(_state).klass('grouped-items-area'));
83134 selection.selectAll('.wrap-form-field input').on('keydown', function (d3_event) {
83135 // if user presses enter, and combobox is not active, accept edits..
83136 if (d3_event.keyCode === 13 && // ↩ Return
83137 context.container().select('.combobox').empty()) {
83138 context.enter(modeBrowse(context));
83143 section.presets = function (val) {
83144 if (!arguments.length) return _presets;
83146 if (!_presets || !val || !utilArrayIdentical(_presets, val)) {
83154 section.state = function (val) {
83155 if (!arguments.length) return _state;
83160 section.tags = function (val) {
83161 if (!arguments.length) return _tags;
83162 _tags = val; // Don't reset _fieldsArr here.
83167 section.entityIDs = function (val) {
83168 if (!arguments.length) return _entityIDs;
83170 if (!val || !_entityIDs || !utilArrayIdentical(_entityIDs, val)) {
83178 return utilRebind(section, dispatch, 'on');
83181 function uiSectionRawMemberEditor(context) {
83182 var section = uiSection('raw-member-editor', context).shouldDisplay(function () {
83183 if (!_entityIDs || _entityIDs.length !== 1) return false;
83184 var entity = context.hasEntity(_entityIDs[0]);
83185 return entity && entity.type === 'relation';
83186 }).label(function () {
83187 var entity = context.hasEntity(_entityIDs[0]);
83188 if (!entity) return '';
83189 var gt = entity.members.length > _maxMembers ? '>' : '';
83190 var count = gt + entity.members.slice(0, _maxMembers).length;
83191 return _t('inspector.title_count', {
83192 title: _t.html('inspector.members'),
83195 }).disclosureContent(renderDisclosureContent);
83196 var taginfo = services.taginfo;
83200 var _maxMembers = 1000;
83202 function downloadMember(d3_event, d) {
83203 d3_event.preventDefault(); // display the loading indicator
83205 select(this.parentNode).classed('tag-reference-loading', true);
83206 context.loadEntity(d.id, function () {
83207 section.reRender();
83211 function zoomToMember(d3_event, d) {
83212 d3_event.preventDefault();
83213 var entity = context.entity(d.id);
83214 context.map().zoomToEase(entity); // highlight the feature in case it wasn't previously on-screen
83216 utilHighlightEntities([d.id], true, context);
83219 function selectMember(d3_event, d) {
83220 d3_event.preventDefault(); // remove the hover-highlight styling
83222 utilHighlightEntities([d.id], false, context);
83223 var entity = context.entity(d.id);
83224 var mapExtent = context.map().extent();
83226 if (!entity.intersects(mapExtent, context.graph())) {
83227 // zoom to the entity if its extent is not visible now
83228 context.map().zoomToEase(entity);
83231 context.enter(modeSelect(context, [d.id]));
83234 function changeRole(d3_event, d) {
83235 var oldRole = d.role;
83236 var newRole = context.cleanRelationRole(select(this).property('value'));
83238 if (oldRole !== newRole) {
83244 context.perform(actionChangeMember(d.relation.id, member, d.index), _t('operations.change_role.annotation', {
83247 context.validator().validate();
83251 function deleteMember(d3_event, d) {
83252 // remove the hover-highlight styling
83253 utilHighlightEntities([d.id], false, context);
83254 context.perform(actionDeleteMember(d.relation.id, d.index), _t('operations.delete_member.annotation', {
83258 if (!context.hasEntity(d.relation.id)) {
83259 // Removing the last member will also delete the relation.
83260 // If this happens we need to exit the selection mode
83261 context.enter(modeBrowse(context));
83263 // Changing the mode also runs `validate`, but otherwise we need to
83264 // rerun it manually
83265 context.validator().validate();
83269 function renderDisclosureContent(selection) {
83270 var entityID = _entityIDs[0];
83271 var memberships = [];
83272 var entity = context.entity(entityID);
83273 entity.members.slice(0, _maxMembers).forEach(function (member, index) {
83280 member: context.hasEntity(member.id),
83281 domId: utilUniqueDomId(entityID + '-member-' + index)
83284 var list = selection.selectAll('.member-list').data([0]);
83285 list = list.enter().append('ul').attr('class', 'member-list').merge(list);
83286 var items = list.selectAll('li').data(memberships, function (d) {
83287 return osmEntity.key(d.relation) + ',' + d.index + ',' + (d.member ? osmEntity.key(d.member) : 'incomplete');
83289 items.exit().each(unbind).remove();
83290 var itemsEnter = items.enter().append('li').attr('class', 'member-row form-field').classed('member-incomplete', function (d) {
83293 itemsEnter.each(function (d) {
83294 var item = select(this);
83295 var label = item.append('label').attr('class', 'field-label').attr('for', d.domId);
83298 // highlight the member feature in the map while hovering on the list item
83299 item.on('mouseover', function () {
83300 utilHighlightEntities([d.id], true, context);
83301 }).on('mouseout', function () {
83302 utilHighlightEntities([d.id], false, context);
83304 var labelLink = label.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectMember);
83305 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
83306 var matched = _mainPresetIndex.match(d.member, context.graph());
83307 return matched && matched.name() || utilDisplayType(d.member.id);
83309 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
83310 return utilDisplayName(d.member);
83312 label.append('button').attr('title', _t('icons.remove')).attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete'));
83313 label.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToMember);
83315 var labelText = label.append('span').attr('class', 'label-text');
83316 labelText.append('span').attr('class', 'member-entity-type').html(_t.html('inspector.' + d.type, {
83319 labelText.append('span').attr('class', 'member-entity-name').html(_t.html('inspector.incomplete', {
83322 label.append('button').attr('class', 'member-download').attr('title', _t('icons.download')).call(svgIcon('#iD-icon-load')).on('click', downloadMember);
83325 var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83326 wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
83328 }).property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto);
83331 wrapEnter.each(bindTypeahead);
83335 items = items.merge(itemsEnter).order();
83336 items.select('input.member-role').property('value', function (d) {
83338 }).on('blur', changeRole).on('change', changeRole);
83339 items.select('button.member-delete').on('click', deleteMember);
83340 var dragOrigin, targetIndex;
83341 items.call(d3_drag().on('start', function (d3_event) {
83346 targetIndex = null;
83347 }).on('drag', function (d3_event) {
83348 var x = d3_event.x - dragOrigin.x,
83349 y = d3_event.y - dragOrigin.y;
83350 if (!select(this).classed('dragging') && // don't display drag until dragging beyond a distance threshold
83351 Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) <= 5) return;
83352 var index = items.nodes().indexOf(this);
83353 select(this).classed('dragging', true);
83354 targetIndex = null;
83355 selection.selectAll('li.member-row').style('transform', function (d2, index2) {
83356 var node = select(this).node();
83358 if (index === index2) {
83359 return 'translate(' + x + 'px, ' + y + 'px)';
83360 } else if (index2 > index && d3_event.y > node.offsetTop) {
83361 if (targetIndex === null || index2 > targetIndex) {
83362 targetIndex = index2;
83365 return 'translateY(-100%)';
83366 } else if (index2 < index && d3_event.y < node.offsetTop + node.offsetHeight) {
83367 if (targetIndex === null || index2 < targetIndex) {
83368 targetIndex = index2;
83371 return 'translateY(100%)';
83376 }).on('end', function (d3_event, d) {
83377 if (!select(this).classed('dragging')) return;
83378 var index = items.nodes().indexOf(this);
83379 select(this).classed('dragging', false);
83380 selection.selectAll('li.member-row').style('transform', null);
83382 if (targetIndex !== null) {
83383 // dragged to a new position, reorder
83384 context.perform(actionMoveMember(d.relation.id, index, targetIndex), _t('operations.reorder_members.annotation'));
83385 context.validator().validate();
83389 function bindTypeahead(d) {
83390 var row = select(this);
83391 var role = row.selectAll('input.member-role');
83392 var origValue = role.property('value');
83394 function sort(value, data) {
83395 var sameletter = [];
83398 for (var i = 0; i < data.length; i++) {
83399 if (data[i].value.substring(0, value.length) === value) {
83400 sameletter.push(data[i]);
83402 other.push(data[i]);
83406 return sameletter.concat(other);
83409 role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
83410 // The `geometry` param is used in the `taginfo.js` interface for
83411 // filtering results, as a key into the `tag_members_fractions`
83412 // object. If we don't know the geometry because the member is
83413 // not yet downloaded, it's ok to guess based on type.
83417 geometry = context.graph().geometry(d.member.id);
83418 } else if (d.type === 'relation') {
83419 geometry = 'relation';
83420 } else if (d.type === 'way') {
83423 geometry = 'point';
83426 var rtype = entity.tags.type;
83429 rtype: rtype || '',
83430 geometry: geometry,
83432 }, function (err, data) {
83433 if (!err) callback(sort(role, data));
83435 }).on('cancel', function () {
83436 role.property('value', origValue);
83440 function unbind() {
83441 var row = select(this);
83442 row.selectAll('input.member-role').call(uiCombobox.off, context);
83446 section.entityIDs = function (val) {
83447 if (!arguments.length) return _entityIDs;
83455 function actionDeleteMembers(relationId, memberIndexes) {
83456 return function (graph) {
83457 // Remove the members in descending order so removals won't shift what members
83458 // are at the remaining indexes
83459 memberIndexes.sort(function (a, b) {
83463 for (var i in memberIndexes) {
83464 graph = actionDeleteMember(relationId, memberIndexes[i])(graph);
83471 function uiSectionRawMembershipEditor(context) {
83472 var section = uiSection('raw-membership-editor', context).shouldDisplay(function () {
83473 return _entityIDs && _entityIDs.length;
83474 }).label(function () {
83475 var parents = getSharedParentRelations();
83476 var gt = parents.length > _maxMemberships ? '>' : '';
83477 var count = gt + parents.slice(0, _maxMemberships).length;
83478 return _t('inspector.title_count', {
83479 title: _t.html('inspector.relations'),
83482 }).disclosureContent(renderDisclosureContent);
83483 var taginfo = services.taginfo;
83484 var nearbyCombo = uiCombobox(context, 'parent-relation').minItems(1).fetcher(fetchNearbyRelations).itemsMouseEnter(function (d3_event, d) {
83485 if (d.relation) utilHighlightEntities([d.relation.id], true, context);
83486 }).itemsMouseLeave(function (d3_event, d) {
83487 if (d.relation) utilHighlightEntities([d.relation.id], false, context);
83489 var _inChange = false;
83490 var _entityIDs = [];
83494 var _maxMemberships = 1000;
83496 function getSharedParentRelations() {
83499 for (var i = 0; i < _entityIDs.length; i++) {
83500 var entity = context.graph().hasEntity(_entityIDs[i]);
83501 if (!entity) continue;
83504 parents = context.graph().parentRelations(entity);
83506 parents = utilArrayIntersection(parents, context.graph().parentRelations(entity));
83509 if (!parents.length) break;
83515 function getMemberships() {
83516 var memberships = [];
83517 var relations = getSharedParentRelations().slice(0, _maxMemberships);
83518 var isMultiselect = _entityIDs.length > 1;
83519 var i, relation, membership, index, member, indexedMember;
83521 for (i = 0; i < relations.length; i++) {
83522 relation = relations[i];
83524 relation: relation,
83526 hash: osmEntity.key(relation)
83529 for (index = 0; index < relation.members.length; index++) {
83530 member = relation.members[index];
83532 if (_entityIDs.indexOf(member.id) !== -1) {
83533 indexedMember = Object.assign({}, member, {
83536 membership.members.push(indexedMember);
83537 membership.hash += ',' + index.toString();
83539 if (!isMultiselect) {
83540 // For single selections, list one entry per membership per relation.
83541 // For multiselections, list one entry per relation.
83542 memberships.push(membership);
83544 relation: relation,
83546 hash: osmEntity.key(relation)
83552 if (membership.members.length) memberships.push(membership);
83555 memberships.forEach(function (membership) {
83556 membership.domId = utilUniqueDomId('membership-' + membership.relation.id);
83558 membership.members.forEach(function (member) {
83559 if (roles.indexOf(member.role) === -1) roles.push(member.role);
83561 membership.role = roles.length === 1 ? roles[0] : roles;
83563 return memberships;
83566 function selectRelation(d3_event, d) {
83567 d3_event.preventDefault(); // remove the hover-highlight styling
83569 utilHighlightEntities([d.relation.id], false, context);
83570 context.enter(modeSelect(context, [d.relation.id]));
83573 function zoomToRelation(d3_event, d) {
83574 d3_event.preventDefault();
83575 var entity = context.entity(d.relation.id);
83576 context.map().zoomToEase(entity); // highlight the relation in case it wasn't previously on-screen
83578 utilHighlightEntities([d.relation.id], true, context);
83581 function changeRole(d3_event, d) {
83582 if (d === 0) return; // called on newrow (shouldn't happen)
83584 if (_inChange) return; // avoid accidental recursive call #5731
83586 var newRole = context.cleanRelationRole(select(this).property('value'));
83587 if (!newRole.trim() && typeof d.role !== 'string') return;
83588 var membersToUpdate = d.members.filter(function (member) {
83589 return member.role !== newRole;
83592 if (membersToUpdate.length) {
83594 context.perform(function actionChangeMemberRoles(graph) {
83595 membersToUpdate.forEach(function (member) {
83596 var newMember = Object.assign({}, member, {
83599 delete newMember.index;
83600 graph = actionChangeMember(d.relation.id, newMember, member.index)(graph);
83603 }, _t('operations.change_role.annotation', {
83604 n: membersToUpdate.length
83606 context.validator().validate();
83612 function addMembership(d, role) {
83613 this.blur(); // avoid keeping focus on the button
83615 _showBlank = false;
83617 function actionAddMembers(relationId, ids, role) {
83618 return function (graph) {
83619 for (var i in ids) {
83622 type: graph.entity(ids[i]).type,
83625 graph = actionAddMember(relationId, member)(graph);
83633 context.perform(actionAddMembers(d.relation.id, _entityIDs, role), _t('operations.add_member.annotation', {
83634 n: _entityIDs.length
83636 context.validator().validate();
83638 var relation = osmRelation();
83639 context.perform(actionAddEntity(relation), actionAddMembers(relation.id, _entityIDs, role), _t('operations.add.annotation.relation')); // changing the mode also runs `validate`
83641 context.enter(modeSelect(context, [relation.id]).newFeature(true));
83645 function deleteMembership(d3_event, d) {
83646 this.blur(); // avoid keeping focus on the button
83648 if (d === 0) return; // called on newrow (shouldn't happen)
83649 // remove the hover-highlight styling
83651 utilHighlightEntities([d.relation.id], false, context);
83652 var indexes = d.members.map(function (member) {
83653 return member.index;
83655 context.perform(actionDeleteMembers(d.relation.id, indexes), _t('operations.delete_member.annotation', {
83656 n: _entityIDs.length
83658 context.validator().validate();
83661 function fetchNearbyRelations(q, callback) {
83662 var newRelation = {
83664 value: _t('inspector.new_relation'),
83665 display: _t.html('inspector.new_relation')
83667 var entityID = _entityIDs[0];
83669 var graph = context.graph();
83671 function baseDisplayLabel(entity) {
83672 var matched = _mainPresetIndex.match(entity, graph);
83673 var presetName = matched && matched.name() || _t('inspector.relation');
83674 var entityName = utilDisplayName(entity) || '';
83675 return presetName + ' ' + entityName;
83678 var explicitRelation = q && context.hasEntity(q.toLowerCase());
83680 if (explicitRelation && explicitRelation.type === 'relation' && explicitRelation.id !== entityID) {
83681 // loaded relation is specified explicitly, only show that
83683 relation: explicitRelation,
83684 value: baseDisplayLabel(explicitRelation) + ' ' + explicitRelation.id
83687 context.history().intersects(context.map().extent()).forEach(function (entity) {
83688 if (entity.type !== 'relation' || entity.id === entityID) return;
83689 var value = baseDisplayLabel(entity);
83690 if (q && (value + ' ' + entity.id).toLowerCase().indexOf(q.toLowerCase()) === -1) return;
83696 result.sort(function (a, b) {
83697 return osmRelation.creationOrder(a.relation, b.relation);
83698 }); // Dedupe identical names by appending relation id - see #2891
83700 var dupeGroups = Object.values(utilArrayGroupBy(result, 'value')).filter(function (v) {
83701 return v.length > 1;
83703 dupeGroups.forEach(function (group) {
83704 group.forEach(function (obj) {
83705 obj.value += ' ' + obj.relation.id;
83710 result.forEach(function (obj) {
83711 obj.title = obj.value;
83713 result.unshift(newRelation);
83717 function renderDisclosureContent(selection) {
83718 var memberships = getMemberships();
83719 var list = selection.selectAll('.member-list').data([0]);
83720 list = list.enter().append('ul').attr('class', 'member-list').merge(list);
83721 var items = list.selectAll('li.member-row-normal').data(memberships, function (d) {
83724 items.exit().each(unbind).remove(); // Enter
83726 var itemsEnter = items.enter().append('li').attr('class', 'member-row member-row-normal form-field'); // highlight the relation in the map while hovering on the list item
83728 itemsEnter.on('mouseover', function (d3_event, d) {
83729 utilHighlightEntities([d.relation.id], true, context);
83730 }).on('mouseout', function (d3_event, d) {
83731 utilHighlightEntities([d.relation.id], false, context);
83733 var labelEnter = itemsEnter.append('label').attr('class', 'field-label').attr('for', function (d) {
83736 var labelLink = labelEnter.append('span').attr('class', 'label-text').append('a').attr('href', '#').on('click', selectRelation);
83737 labelLink.append('span').attr('class', 'member-entity-type').html(function (d) {
83738 var matched = _mainPresetIndex.match(d.relation, context.graph());
83739 return matched && matched.name() || _t('inspector.relation');
83741 labelLink.append('span').attr('class', 'member-entity-name').html(function (d) {
83742 return utilDisplayName(d.relation);
83744 labelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', deleteMembership);
83745 labelEnter.append('button').attr('class', 'member-zoom').attr('title', _t('icons.zoom_to')).call(svgIcon('#iD-icon-framed-dot', 'monochrome')).on('click', zoomToRelation);
83746 var wrapEnter = itemsEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83747 wrapEnter.append('input').attr('class', 'member-role').attr('id', function (d) {
83749 }).property('type', 'text').property('value', function (d) {
83750 return typeof d.role === 'string' ? d.role : '';
83751 }).attr('title', function (d) {
83752 return Array.isArray(d.role) ? d.role.filter(Boolean).join('\n') : d.role;
83753 }).attr('placeholder', function (d) {
83754 return Array.isArray(d.role) ? _t('inspector.multiple_roles') : _t('inspector.role');
83755 }).classed('mixed', function (d) {
83756 return Array.isArray(d.role);
83757 }).call(utilNoAuto).on('blur', changeRole).on('change', changeRole);
83760 wrapEnter.each(bindTypeahead);
83763 var newMembership = list.selectAll('.member-row-new').data(_showBlank ? [0] : []); // Exit
83765 newMembership.exit().remove(); // Enter
83767 var newMembershipEnter = newMembership.enter().append('li').attr('class', 'member-row member-row-new form-field');
83768 var newLabelEnter = newMembershipEnter.append('label').attr('class', 'field-label');
83769 newLabelEnter.append('input').attr('placeholder', _t('inspector.choose_relation')).attr('type', 'text').attr('class', 'member-entity-input').call(utilNoAuto);
83770 newLabelEnter.append('button').attr('class', 'remove member-delete').call(svgIcon('#iD-operation-delete')).on('click', function () {
83771 list.selectAll('.member-row-new').remove();
83773 var newWrapEnter = newMembershipEnter.append('div').attr('class', 'form-field-input-wrap form-field-input-member');
83774 newWrapEnter.append('input').attr('class', 'member-role').property('type', 'text').attr('placeholder', _t('inspector.role')).call(utilNoAuto); // Update
83776 newMembership = newMembership.merge(newMembershipEnter);
83777 newMembership.selectAll('.member-entity-input').on('blur', cancelEntity) // if it wasn't accepted normally, cancel it
83778 .call(nearbyCombo.on('accept', acceptEntity).on('cancel', cancelEntity)); // Container for the Add button
83780 var addRow = selection.selectAll('.add-row').data([0]); // enter
83782 var addRowEnter = addRow.enter().append('div').attr('class', 'add-row');
83783 var addRelationButton = addRowEnter.append('button').attr('class', 'add-relation');
83784 addRelationButton.call(svgIcon('#iD-icon-plus', 'light'));
83785 addRelationButton.call(uiTooltip().title(_t.html('inspector.add_to_relation')).placement(_mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left'));
83786 addRowEnter.append('div').attr('class', 'space-value'); // preserve space
83788 addRowEnter.append('div').attr('class', 'space-buttons'); // preserve space
83791 addRow = addRow.merge(addRowEnter);
83792 addRow.select('.add-relation').on('click', function () {
83794 section.reRender();
83795 list.selectAll('.member-entity-input').node().focus();
83798 function acceptEntity(d) {
83802 } // remove hover-higlighting
83805 if (d.relation) utilHighlightEntities([d.relation.id], false, context);
83806 var role = context.cleanRelationRole(list.selectAll('.member-row-new .member-role').property('value'));
83807 addMembership(d, role);
83810 function cancelEntity() {
83811 var input = newMembership.selectAll('.member-entity-input');
83812 input.property('value', ''); // remove hover-higlighting
83814 context.surface().selectAll('.highlighted').classed('highlighted', false);
83817 function bindTypeahead(d) {
83818 var row = select(this);
83819 var role = row.selectAll('input.member-role');
83820 var origValue = role.property('value');
83822 function sort(value, data) {
83823 var sameletter = [];
83826 for (var i = 0; i < data.length; i++) {
83827 if (data[i].value.substring(0, value.length) === value) {
83828 sameletter.push(data[i]);
83830 other.push(data[i]);
83834 return sameletter.concat(other);
83837 role.call(uiCombobox(context, 'member-role').fetcher(function (role, callback) {
83838 var rtype = d.relation.tags.type;
83841 rtype: rtype || '',
83842 geometry: context.graph().geometry(_entityIDs[0]),
83844 }, function (err, data) {
83845 if (!err) callback(sort(role, data));
83847 }).on('cancel', function () {
83848 role.property('value', origValue);
83852 function unbind() {
83853 var row = select(this);
83854 row.selectAll('input.member-role').call(uiCombobox.off, context);
83858 section.entityIDs = function (val) {
83859 if (!arguments.length) return _entityIDs;
83861 _showBlank = false;
83868 function uiSectionSelectionList(context) {
83869 var _selectedIDs = [];
83870 var section = uiSection('selected-features', context).shouldDisplay(function () {
83871 return _selectedIDs.length > 1;
83872 }).label(function () {
83873 return _t('inspector.title_count', {
83874 title: _t.html('inspector.features'),
83875 count: _selectedIDs.length
83877 }).disclosureContent(renderDisclosureContent);
83878 context.history().on('change.selectionList', function (difference) {
83880 section.reRender();
83884 section.entityIDs = function (val) {
83885 if (!arguments.length) return _selectedIDs;
83886 _selectedIDs = val;
83890 function selectEntity(d3_event, entity) {
83891 context.enter(modeSelect(context, [entity.id]));
83894 function deselectEntity(d3_event, entity) {
83895 var selectedIDs = _selectedIDs.slice();
83897 var index = selectedIDs.indexOf(entity.id);
83900 selectedIDs.splice(index, 1);
83901 context.enter(modeSelect(context, selectedIDs));
83905 function renderDisclosureContent(selection) {
83906 var list = selection.selectAll('.feature-list').data([0]);
83907 list = list.enter().append('ul').attr('class', 'feature-list').merge(list);
83909 var entities = _selectedIDs.map(function (id) {
83910 return context.hasEntity(id);
83911 }).filter(Boolean);
83913 var items = list.selectAll('.feature-list-item').data(entities, osmEntity.key);
83914 items.exit().remove(); // Enter
83916 var enter = items.enter().append('li').attr('class', 'feature-list-item').each(function (d) {
83917 select(this).on('mouseover', function () {
83918 utilHighlightEntities([d.id], true, context);
83919 }).on('mouseout', function () {
83920 utilHighlightEntities([d.id], false, context);
83923 var label = enter.append('button').attr('class', 'label').on('click', selectEntity);
83924 label.append('span').attr('class', 'entity-geom-icon').call(svgIcon('', 'pre-text'));
83925 label.append('span').attr('class', 'entity-type');
83926 label.append('span').attr('class', 'entity-name');
83927 enter.append('button').attr('class', 'close').attr('title', _t('icons.deselect')).on('click', deselectEntity).call(svgIcon('#iD-icon-close')); // Update
83929 items = items.merge(enter);
83930 items.selectAll('.entity-geom-icon use').attr('href', function () {
83931 var entity = this.parentNode.parentNode.__data__;
83932 return '#iD-icon-' + entity.geometry(context.graph());
83934 items.selectAll('.entity-type').html(function (entity) {
83935 return _mainPresetIndex.match(entity, context.graph()).name();
83937 items.selectAll('.entity-name').html(function (d) {
83938 // fetch latest entity
83939 var entity = context.entity(d.id);
83940 return utilDisplayName(entity);
83947 function uiEntityEditor(context) {
83948 var dispatch = dispatch$8('choose');
83949 var _state = 'select';
83950 var _coalesceChanges = false;
83951 var _modified = false;
83957 var _activePresets = [];
83963 function entityEditor(selection) {
83964 var combinedTags = utilCombinedTags(_entityIDs, context.graph()); // Header
83966 var header = selection.selectAll('.header').data([0]); // Enter
83968 var headerEnter = header.enter().append('div').attr('class', 'header fillL');
83969 headerEnter.append('button').attr('class', 'preset-reset preset-choose').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-forward' : '#iD-icon-backward'));
83970 headerEnter.append('button').attr('class', 'close').on('click', function () {
83971 context.enter(modeBrowse(context));
83972 }).call(svgIcon(_modified ? '#iD-icon-apply' : '#iD-icon-close'));
83973 headerEnter.append('h3'); // Update
83975 header = header.merge(headerEnter);
83976 header.selectAll('h3').html(_entityIDs.length === 1 ? _t.html('inspector.edit') : _t.html('inspector.edit_features'));
83977 header.selectAll('.preset-reset').on('click', function () {
83978 dispatch.call('choose', this, _activePresets);
83981 var body = selection.selectAll('.inspector-body').data([0]); // Enter
83983 var bodyEnter = body.enter().append('div').attr('class', 'entity-editor inspector-body sep-top'); // Update
83985 body = body.merge(bodyEnter);
83988 _sections = [uiSectionSelectionList(context), uiSectionFeatureType(context).on('choose', function (presets) {
83989 dispatch.call('choose', this, presets);
83990 }), uiSectionEntityIssues(context), uiSectionPresetFields(context).on('change', changeTags).on('revert', revertTags), uiSectionRawTagEditor('raw-tag-editor', context).on('change', changeTags), uiSectionRawMemberEditor(context), uiSectionRawMembershipEditor(context)];
83993 _sections.forEach(function (section) {
83994 if (section.entityIDs) {
83995 section.entityIDs(_entityIDs);
83998 if (section.presets) {
83999 section.presets(_activePresets);
84002 if (section.tags) {
84003 section.tags(combinedTags);
84006 if (section.state) {
84007 section.state(_state);
84010 body.call(section.render);
84013 context.history().on('change.entity-editor', historyChanged);
84015 function historyChanged(difference) {
84016 if (selection.selectAll('.entity-editor').empty()) return;
84017 if (_state === 'hide') return;
84018 var significant = !difference || difference.didChange.properties || difference.didChange.addition || difference.didChange.deletion;
84019 if (!significant) return;
84020 _entityIDs = _entityIDs.filter(context.hasEntity);
84021 if (!_entityIDs.length) return;
84022 var priorActivePreset = _activePresets.length === 1 && _activePresets[0];
84023 loadActivePresets();
84024 var graph = context.graph();
84025 entityEditor.modified(_base !== graph);
84026 entityEditor(selection);
84028 if (priorActivePreset && _activePresets.length === 1 && priorActivePreset !== _activePresets[0]) {
84029 // flash the button to indicate the preset changed
84030 context.container().selectAll('.entity-editor button.preset-reset .label').style('background-color', '#fff').transition().duration(750).style('background-color', null);
84033 } // Tag changes that fire on input can all get coalesced into a single
84034 // history operation when the user leaves the field. #2342
84035 // Use explicit entityIDs in case the selection changes before the event is fired.
84038 function changeTags(entityIDs, changed, onInput) {
84041 for (var i in entityIDs) {
84042 var entityID = entityIDs[i];
84043 var entity = context.entity(entityID);
84044 var tags = Object.assign({}, entity.tags); // shallow copy
84046 for (var k in changed) {
84048 var v = changed[k];
84050 if (v !== undefined || tags.hasOwnProperty(k)) {
84056 tags = utilCleanTags(tags);
84059 if (!fastDeepEqual(entity.tags, tags)) {
84060 actions.push(actionChangeTags(entityID, tags));
84064 if (actions.length) {
84065 var combinedAction = function combinedAction(graph) {
84066 actions.forEach(function (action) {
84067 graph = action(graph);
84072 var annotation = _t('operations.change_tags.annotation');
84074 if (_coalesceChanges) {
84075 context.overwrite(combinedAction, annotation);
84077 context.perform(combinedAction, annotation);
84078 _coalesceChanges = !!onInput;
84080 } // if leaving field (blur event), rerun validation
84084 context.validator().validate();
84088 function revertTags(keys) {
84091 for (var i in _entityIDs) {
84092 var entityID = _entityIDs[i];
84093 var original = context.graph().base().entities[entityID];
84096 for (var j in keys) {
84098 changed[key] = original ? original.tags[key] : undefined;
84101 var entity = context.entity(entityID);
84102 var tags = Object.assign({}, entity.tags); // shallow copy
84104 for (var k in changed) {
84106 var v = changed[k];
84108 if (v !== undefined || tags.hasOwnProperty(k)) {
84113 tags = utilCleanTags(tags);
84115 if (!fastDeepEqual(entity.tags, tags)) {
84116 actions.push(actionChangeTags(entityID, tags));
84120 if (actions.length) {
84121 var combinedAction = function combinedAction(graph) {
84122 actions.forEach(function (action) {
84123 graph = action(graph);
84128 var annotation = _t('operations.change_tags.annotation');
84130 if (_coalesceChanges) {
84131 context.overwrite(combinedAction, annotation);
84133 context.perform(combinedAction, annotation);
84134 _coalesceChanges = false;
84138 context.validator().validate();
84141 entityEditor.modified = function (val) {
84142 if (!arguments.length) return _modified;
84144 return entityEditor;
84147 entityEditor.state = function (val) {
84148 if (!arguments.length) return _state;
84150 return entityEditor;
84153 entityEditor.entityIDs = function (val) {
84154 if (!arguments.length) return _entityIDs; // always reload these even if the entityIDs are unchanged, since we
84155 // could be reselecting after something like dragging a node
84157 _base = context.graph();
84158 _coalesceChanges = false;
84159 if (val && _entityIDs && utilArrayIdentical(_entityIDs, val)) return entityEditor; // exit early if no change
84162 loadActivePresets(true);
84163 return entityEditor.modified(false);
84166 entityEditor.newFeature = function (val) {
84167 if (!arguments.length) return _newFeature;
84169 return entityEditor;
84172 function loadActivePresets(isForNewSelection) {
84173 var graph = context.graph();
84176 for (var i in _entityIDs) {
84177 var entity = graph.hasEntity(_entityIDs[i]);
84178 if (!entity) return;
84179 var match = _mainPresetIndex.match(entity, graph);
84180 if (!counts[match.id]) counts[match.id] = 0;
84181 counts[match.id] += 1;
84184 var matches = Object.keys(counts).sort(function (p1, p2) {
84185 return counts[p2] - counts[p1];
84186 }).map(function (pID) {
84187 return _mainPresetIndex.item(pID);
84190 if (!isForNewSelection) {
84191 // A "weak" preset doesn't set any tags. (e.g. "Address")
84192 var weakPreset = _activePresets.length === 1 && !_activePresets[0].isFallback() && Object.keys(_activePresets[0].addTags || {}).length === 0; // Don't replace a weak preset with a fallback preset (e.g. "Point")
84194 if (weakPreset && matches.length === 1 && matches[0].isFallback()) return;
84197 entityEditor.presets(matches);
84200 entityEditor.presets = function (val) {
84201 if (!arguments.length) return _activePresets; // don't reload the same preset
84203 if (!utilArrayIdentical(val, _activePresets)) {
84204 _activePresets = val;
84207 return entityEditor;
84210 return utilRebind(entityEditor, dispatch, 'on');
84213 function uiPresetList(context) {
84214 var dispatch = dispatch$8('cancel', 'choose');
84220 var _currentPresets;
84222 var _autofocus = false;
84224 function presetList(selection) {
84225 if (!_entityIDs) return;
84226 var presets = _mainPresetIndex.matchAllGeometry(entityGeometries());
84227 selection.html('');
84228 var messagewrap = selection.append('div').attr('class', 'header fillL');
84229 var message = messagewrap.append('h3').html(_t.html('inspector.choose'));
84230 messagewrap.append('button').attr('class', 'preset-choose').on('click', function () {
84231 dispatch.call('cancel', this);
84232 }).call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward'));
84234 function initialKeydown(d3_event) {
84235 // hack to let delete shortcut work when search is autofocused
84236 if (search.property('value').length === 0 && (d3_event.keyCode === utilKeybinding.keyCodes['⌫'] || d3_event.keyCode === utilKeybinding.keyCodes['⌦'])) {
84237 d3_event.preventDefault();
84238 d3_event.stopPropagation();
84239 operationDelete(context, _entityIDs)(); // hack to let undo work when search is autofocused
84240 } else if (search.property('value').length === 0 && (d3_event.ctrlKey || d3_event.metaKey) && d3_event.keyCode === utilKeybinding.keyCodes.z) {
84241 d3_event.preventDefault();
84242 d3_event.stopPropagation();
84244 } else if (!d3_event.ctrlKey && !d3_event.metaKey) {
84245 // don't check for delete/undo hack on future keydown events
84246 select(this).on('keydown', keydown);
84247 keydown.call(this, d3_event);
84251 function keydown(d3_event) {
84253 if (d3_event.keyCode === utilKeybinding.keyCodes['↓'] && // if insertion point is at the end of the string
84254 search.node().selectionStart === search.property('value').length) {
84255 d3_event.preventDefault();
84256 d3_event.stopPropagation(); // move focus to the first item in the preset list
84258 var buttons = list.selectAll('.preset-list-button');
84259 if (!buttons.empty()) buttons.nodes()[0].focus();
84263 function keypress(d3_event) {
84265 var value = search.property('value');
84267 if (d3_event.keyCode === 13 && // ↩ Return
84269 list.selectAll('.preset-list-item:first-child').each(function (d) {
84270 d.choose.call(this);
84275 function inputevent() {
84276 var value = search.property('value');
84277 list.classed('filtered', value.length);
84278 var results, messageText;
84280 if (value.length) {
84281 results = presets.search(value, entityGeometries()[0], _currLoc);
84282 messageText = _t('inspector.results', {
84283 n: results.collection.length,
84287 results = _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc);
84288 messageText = _t('inspector.choose');
84291 list.call(drawList, results);
84292 message.html(messageText);
84295 var searchWrap = selection.append('div').attr('class', 'search-header');
84296 searchWrap.call(svgIcon('#iD-icon-search', 'pre-text'));
84297 var search = searchWrap.append('input').attr('class', 'preset-search-input').attr('placeholder', _t('inspector.search')).attr('type', 'search').call(utilNoAuto).on('keydown', initialKeydown).on('keypress', keypress).on('input', debounce(inputevent));
84300 search.node().focus(); // Safari 14 doesn't always like to focus immediately,
84301 // so try again on the next pass
84303 setTimeout(function () {
84304 search.node().focus();
84308 var listWrap = selection.append('div').attr('class', 'inspector-body');
84309 var list = listWrap.append('div').attr('class', 'preset-list').call(drawList, _mainPresetIndex.defaults(entityGeometries()[0], 36, !context.inIntro(), _currLoc));
84310 context.features().on('change.preset-list', updateForFeatureHiddenState);
84313 function drawList(list, presets) {
84314 presets = presets.matchAllGeometry(entityGeometries());
84315 var collection = presets.collection.reduce(function (collection, preset) {
84316 if (!preset) return collection;
84318 if (preset.members) {
84319 if (preset.members.collection.filter(function (preset) {
84320 return preset.addable();
84322 collection.push(CategoryItem(preset));
84324 } else if (preset.addable()) {
84325 collection.push(PresetItem(preset));
84330 var items = list.selectAll('.preset-list-item').data(collection, function (d) {
84331 return d.preset.id;
84334 items.exit().remove();
84335 items.enter().append('div').attr('class', function (item) {
84336 return 'preset-list-item preset-' + item.preset.id.replace('/', '-');
84337 }).classed('current', function (item) {
84338 return _currentPresets.indexOf(item.preset) !== -1;
84339 }).each(function (item) {
84340 select(this).call(item);
84341 }).style('opacity', 0).transition().style('opacity', 1);
84342 updateForFeatureHiddenState();
84345 function itemKeydown(d3_event) {
84346 // the actively focused item
84347 var item = select(this.closest('.preset-list-item'));
84348 var parentItem = select(item.node().parentNode.closest('.preset-list-item')); // arrow down, move focus to the next, lower item
84350 if (d3_event.keyCode === utilKeybinding.keyCodes['↓']) {
84351 d3_event.preventDefault();
84352 d3_event.stopPropagation(); // the next item in the list at the same level
84354 var nextItem = select(item.node().nextElementSibling); // if there is no next item in this list
84356 if (nextItem.empty()) {
84357 // if there is a parent item
84358 if (!parentItem.empty()) {
84359 // the item is the last item of a sublist,
84360 // select the next item at the parent level
84361 nextItem = select(parentItem.node().nextElementSibling);
84362 } // if the focused item is expanded
84364 } else if (select(this).classed('expanded')) {
84365 // select the first subitem instead
84366 nextItem = item.select('.subgrid .preset-list-item:first-child');
84369 if (!nextItem.empty()) {
84370 // focus on the next item
84371 nextItem.select('.preset-list-button').node().focus();
84372 } // arrow up, move focus to the previous, higher item
84374 } else if (d3_event.keyCode === utilKeybinding.keyCodes['↑']) {
84375 d3_event.preventDefault();
84376 d3_event.stopPropagation(); // the previous item in the list at the same level
84378 var previousItem = select(item.node().previousElementSibling); // if there is no previous item in this list
84380 if (previousItem.empty()) {
84381 // if there is a parent item
84382 if (!parentItem.empty()) {
84383 // the item is the first subitem of a sublist select the parent item
84384 previousItem = parentItem;
84385 } // if the previous item is expanded
84387 } else if (previousItem.select('.preset-list-button').classed('expanded')) {
84388 // select the last subitem of the sublist of the previous item
84389 previousItem = previousItem.select('.subgrid .preset-list-item:last-child');
84392 if (!previousItem.empty()) {
84393 // focus on the previous item
84394 previousItem.select('.preset-list-button').node().focus();
84396 // the focus is at the top of the list, move focus back to the search field
84397 var search = select(this.closest('.preset-list-pane')).select('.preset-search-input');
84398 search.node().focus();
84399 } // arrow left, move focus to the parent item if there is one
84401 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
84402 d3_event.preventDefault();
84403 d3_event.stopPropagation(); // if there is a parent item, focus on the parent item
84405 if (!parentItem.empty()) {
84406 parentItem.select('.preset-list-button').node().focus();
84407 } // arrow right, choose this item
84409 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
84410 d3_event.preventDefault();
84411 d3_event.stopPropagation();
84412 item.datum().choose.call(select(this).node());
84416 function CategoryItem(preset) {
84421 function item(selection) {
84422 var wrap = selection.append('div').attr('class', 'preset-list-button-wrap category');
84425 var isExpanded = select(this).classed('expanded');
84426 var iconName = isExpanded ? _mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward' : '#iD-icon-down';
84427 select(this).classed('expanded', !isExpanded);
84428 select(this).selectAll('div.label-inner svg.icon use').attr('href', iconName);
84432 var geometries = entityGeometries();
84433 var button = wrap.append('button').attr('class', 'preset-list-button').classed('expanded', false).call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on('click', click).on('keydown', function (d3_event) {
84434 // right arrow, expand the focused item
84435 if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '←' : '→']) {
84436 d3_event.preventDefault();
84437 d3_event.stopPropagation(); // if the item isn't expanded
84439 if (!select(this).classed('expanded')) {
84440 // toggle expansion (expand the item)
84441 click.call(this, d3_event);
84442 } // left arrow, collapse the focused item
84444 } else if (d3_event.keyCode === utilKeybinding.keyCodes[_mainLocalizer.textDirection() === 'rtl' ? '→' : '←']) {
84445 d3_event.preventDefault();
84446 d3_event.stopPropagation(); // if the item is expanded
84448 if (select(this).classed('expanded')) {
84449 // toggle expansion (collapse the item)
84450 click.call(this, d3_event);
84453 itemKeydown.call(this, d3_event);
84456 var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
84457 label.append('div').attr('class', 'namepart').call(svgIcon(_mainLocalizer.textDirection() === 'rtl' ? '#iD-icon-backward' : '#iD-icon-forward', 'inline')).append('span').html(function () {
84458 return preset.nameLabel() + '…';
84460 box = selection.append('div').attr('class', 'subgrid').style('max-height', '0px').style('opacity', 0);
84461 box.append('div').attr('class', 'arrow');
84462 sublist = box.append('div').attr('class', 'preset-list fillL3');
84465 item.choose = function () {
84466 if (!box || !sublist) return;
84470 box.transition().duration(200).style('opacity', '0').style('max-height', '0px').style('padding-bottom', '0px');
84473 var members = preset.members.matchAllGeometry(entityGeometries());
84474 sublist.call(drawList, members);
84475 box.transition().duration(200).style('opacity', '1').style('max-height', 200 + members.collection.length * 190 + 'px').style('padding-bottom', '10px');
84479 item.preset = preset;
84483 function PresetItem(preset) {
84484 function item(selection) {
84485 var wrap = selection.append('div').attr('class', 'preset-list-button-wrap');
84486 var geometries = entityGeometries();
84487 var button = wrap.append('button').attr('class', 'preset-list-button').call(uiPresetIcon().geometry(geometries.length === 1 && geometries[0]).preset(preset)).on('click', item.choose).on('keydown', itemKeydown);
84488 var label = button.append('div').attr('class', 'label').append('div').attr('class', 'label-inner');
84489 var nameparts = [preset.nameLabel(), preset.subtitleLabel()].filter(Boolean);
84490 label.selectAll('.namepart').data(nameparts).enter().append('div').attr('class', 'namepart').html(function (d) {
84493 wrap.call(item.reference.button);
84494 selection.call(item.reference.body);
84497 item.choose = function () {
84498 if (select(this).classed('disabled')) return;
84500 if (!context.inIntro()) {
84501 _mainPresetIndex.setMostRecent(preset, entityGeometries()[0]);
84504 context.perform(function (graph) {
84505 for (var i in _entityIDs) {
84506 var entityID = _entityIDs[i];
84507 var oldPreset = _mainPresetIndex.match(graph.entity(entityID), graph);
84508 graph = actionChangePreset(entityID, oldPreset, preset)(graph);
84512 }, _t('operations.change_tags.annotation'));
84513 context.validator().validate(); // rerun validation
84515 dispatch.call('choose', this, preset);
84518 item.help = function (d3_event) {
84519 d3_event.stopPropagation();
84520 item.reference.toggle();
84523 item.preset = preset;
84524 item.reference = uiTagReference(preset.reference());
84528 function updateForFeatureHiddenState() {
84529 if (!_entityIDs.every(context.hasEntity)) return;
84530 var geometries = entityGeometries();
84531 var button = context.container().selectAll('.preset-list .preset-list-button'); // remove existing tooltips
84533 button.call(uiTooltip().destroyAny);
84534 button.each(function (item, index) {
84535 var hiddenPresetFeaturesId;
84537 for (var i in geometries) {
84538 hiddenPresetFeaturesId = context.features().isHiddenPreset(item.preset, geometries[i]);
84539 if (hiddenPresetFeaturesId) break;
84542 var isHiddenPreset = !context.inIntro() && !!hiddenPresetFeaturesId && (_currentPresets.length !== 1 || item.preset !== _currentPresets[0]);
84543 select(this).classed('disabled', isHiddenPreset);
84545 if (isHiddenPreset) {
84546 var isAutoHidden = context.features().autoHidden(hiddenPresetFeaturesId);
84547 select(this).call(uiTooltip().title(_t.html('inspector.hidden_preset.' + (isAutoHidden ? 'zoom' : 'manual'), {
84548 features: _t.html('feature.' + hiddenPresetFeaturesId + '.description')
84549 })).placement(index < 2 ? 'bottom' : 'top'));
84554 presetList.autofocus = function (val) {
84555 if (!arguments.length) return _autofocus;
84560 presetList.entityIDs = function (val) {
84561 if (!arguments.length) return _entityIDs;
84565 if (_entityIDs && _entityIDs.length) {
84566 // calculate current location
84567 var extent = _entityIDs.reduce(function (extent, entityID) {
84568 var entity = context.graph().entity(entityID);
84569 return extent.extend(entity.extent(context.graph()));
84572 _currLoc = extent.center(); // match presets
84574 var presets = _entityIDs.map(function (entityID) {
84575 return _mainPresetIndex.match(context.entity(entityID), context.graph());
84578 presetList.presets(presets);
84584 presetList.presets = function (val) {
84585 if (!arguments.length) return _currentPresets;
84586 _currentPresets = val;
84590 function entityGeometries() {
84593 for (var i in _entityIDs) {
84594 var entityID = _entityIDs[i];
84595 var entity = context.entity(entityID);
84596 var geometry = entity.geometry(context.graph()); // Treat entities on addr:interpolation lines as points, not vertices (#3241)
84598 if (geometry === 'vertex' && entity.isOnAddressLine(context.graph())) {
84599 geometry = 'point';
84602 if (!counts[geometry]) counts[geometry] = 0;
84603 counts[geometry] += 1;
84606 return Object.keys(counts).sort(function (geom1, geom2) {
84607 return counts[geom2] - counts[geom1];
84611 return utilRebind(presetList, dispatch, 'on');
84614 function uiViewOnOSM(context) {
84615 var _what; // an osmEntity or osmNote
84618 function viewOnOSM(selection) {
84621 if (_what instanceof osmEntity) {
84622 url = context.connection().entityURL(_what);
84623 } else if (_what instanceof osmNote) {
84624 url = context.connection().noteURL(_what);
84627 var data = !_what || _what.isNew() ? [] : [_what];
84628 var link = selection.selectAll('.view-on-osm').data(data, function (d) {
84632 link.exit().remove(); // enter
84634 var linkEnter = link.enter().append('a').attr('class', 'view-on-osm').attr('target', '_blank').attr('href', url).call(svgIcon('#iD-icon-out-link', 'inline'));
84635 linkEnter.append('span').html(_t.html('inspector.view_on_osm'));
84638 viewOnOSM.what = function (_) {
84639 if (!arguments.length) return _what;
84647 function uiInspector(context) {
84648 var presetList = uiPresetList(context);
84649 var entityEditor = uiEntityEditor(context);
84650 var wrap = select(null),
84651 presetPane = select(null),
84652 editorPane = select(null);
84653 var _state = 'select';
84657 var _newFeature = false;
84659 function inspector(selection) {
84660 presetList.entityIDs(_entityIDs).autofocus(_newFeature).on('choose', inspector.setPreset).on('cancel', function () {
84661 inspector.setPreset();
84663 entityEditor.state(_state).entityIDs(_entityIDs).on('choose', inspector.showList);
84664 wrap = selection.selectAll('.panewrap').data([0]);
84665 var enter = wrap.enter().append('div').attr('class', 'panewrap');
84666 enter.append('div').attr('class', 'preset-list-pane pane');
84667 enter.append('div').attr('class', 'entity-editor-pane pane');
84668 wrap = wrap.merge(enter);
84669 presetPane = wrap.selectAll('.preset-list-pane');
84670 editorPane = wrap.selectAll('.entity-editor-pane');
84672 function shouldDefaultToPresetList() {
84673 // always show the inspector on hover
84674 if (_state !== 'select') return false; // can only change preset on single selection
84676 if (_entityIDs.length !== 1) return false;
84677 var entityID = _entityIDs[0];
84678 var entity = context.hasEntity(entityID);
84679 if (!entity) return false; // default to inspector if there are already tags
84681 if (entity.hasNonGeometryTags()) return false; // prompt to select preset if feature is new and untagged
84683 if (_newFeature) return true; // all existing features except vertices should default to inspector
84685 if (entity.geometry(context.graph()) !== 'vertex') return false; // show vertex relations if any
84687 if (context.graph().parentRelations(entity).length) return false; // show vertex issues if there are any
84689 if (context.validator().getEntityIssues(entityID).length) return false; // show turn retriction editor for junction vertices
84691 if (entity.isHighwayIntersection(context.graph())) return false; // otherwise show preset list for uninteresting vertices
84696 if (shouldDefaultToPresetList()) {
84697 wrap.style('right', '-100%');
84698 editorPane.classed('hide', true);
84699 presetPane.classed('hide', false).call(presetList);
84701 wrap.style('right', '0%');
84702 presetPane.classed('hide', true);
84703 editorPane.classed('hide', false).call(entityEditor);
84706 var footer = selection.selectAll('.footer').data([0]);
84707 footer = footer.enter().append('div').attr('class', 'footer').merge(footer);
84708 footer.call(uiViewOnOSM(context).what(context.hasEntity(_entityIDs.length === 1 && _entityIDs[0])));
84711 inspector.showList = function (presets) {
84712 presetPane.classed('hide', false);
84713 wrap.transition().styleTween('right', function () {
84714 return interpolate$1('0%', '-100%');
84715 }).on('end', function () {
84716 editorPane.classed('hide', true);
84720 presetList.presets(presets);
84723 presetPane.call(presetList.autofocus(true));
84726 inspector.setPreset = function (preset) {
84727 // upon setting multipolygon, go to the area preset list instead of the editor
84728 if (preset && preset.id === 'type/multipolygon') {
84729 presetPane.call(presetList.autofocus(true));
84731 editorPane.classed('hide', false);
84732 wrap.transition().styleTween('right', function () {
84733 return interpolate$1('-100%', '0%');
84734 }).on('end', function () {
84735 presetPane.classed('hide', true);
84739 entityEditor.presets([preset]);
84742 editorPane.call(entityEditor);
84746 inspector.state = function (val) {
84747 if (!arguments.length) return _state;
84749 entityEditor.state(_state); // remove any old field help overlay that might have gotten attached to the inspector
84751 context.container().selectAll('.field-help-body').remove();
84755 inspector.entityIDs = function (val) {
84756 if (!arguments.length) return _entityIDs;
84761 inspector.newFeature = function (val) {
84762 if (!arguments.length) return _newFeature;
84770 function uiImproveOsmComments() {
84773 function issueComments(selection) {
84774 // make the div immediately so it appears above the buttons
84775 var comments = selection.selectAll('.comments-container').data([0]);
84776 comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments); // must retrieve comments from API before they can be displayed
84778 services.improveOSM.getComments(_qaItem).then(function (d) {
84779 if (!d.comments) return; // nothing to do here
84781 var commentEnter = comments.selectAll('.comment').data(d.comments).enter().append('div').attr('class', 'comment');
84782 commentEnter.append('div').attr('class', 'comment-avatar').call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
84783 var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
84784 var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
84785 metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
84786 var osm = services.osm;
84787 var selection = select(this);
84789 if (osm && d.username) {
84790 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.username)).attr('target', '_blank');
84793 selection.html(function (d) {
84797 metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
84798 return _t.html('note.status.commented', {
84799 when: localeDateString(d.timestamp)
84802 mainEnter.append('div').attr('class', 'comment-text').append('p').html(function (d) {
84805 })["catch"](function (err) {
84806 console.log(err); // eslint-disable-line no-console
84810 function localeDateString(s) {
84811 if (!s) return null;
84817 var d = new Date(s * 1000); // timestamp is served in seconds, date takes ms
84819 if (isNaN(d.getTime())) return null;
84820 return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
84823 issueComments.issue = function (val) {
84824 if (!arguments.length) return _qaItem;
84826 return issueComments;
84829 return issueComments;
84832 function uiImproveOsmDetails(context) {
84835 function issueDetail(d) {
84836 if (d.desc) return d.desc;
84837 var issueKey = d.issueKey;
84838 d.replacements = d.replacements || {};
84839 d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
84841 return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".description"), d.replacements);
84844 function improveOsmDetails(selection) {
84845 var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
84846 return "".concat(d.id, "-").concat(d.status || 0);
84848 details.exit().remove();
84849 var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
84851 var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
84852 descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
84853 descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
84855 var relatedEntities = [];
84856 descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
84857 var link = select(this);
84858 var isObjectLink = link.classed('error_object_link');
84859 var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
84860 var entity = context.hasEntity(entityID);
84861 relatedEntities.push(entityID); // Add click handler
84863 link.on('mouseenter', function () {
84864 utilHighlightEntities([entityID], true, context);
84865 }).on('mouseleave', function () {
84866 utilHighlightEntities([entityID], false, context);
84867 }).on('click', function (d3_event) {
84868 d3_event.preventDefault();
84869 utilHighlightEntities([entityID], false, context);
84870 var osmlayer = context.layers().layer('osm');
84872 if (!osmlayer.enabled()) {
84873 osmlayer.enabled(true);
84876 context.map().centerZoom(_qaItem.loc, 20);
84879 context.enter(modeSelect(context, [entityID]));
84881 context.loadEntity(entityID, function (err, result) {
84883 var entity = result.data.find(function (e) {
84884 return e.id === entityID;
84886 if (entity) context.enter(modeSelect(context, [entityID]));
84889 }); // Replace with friendly name if possible
84890 // (The entity may not yet be loaded into the graph)
84893 var name = utilDisplayName(entity); // try to use common name
84895 if (!name && !isObjectLink) {
84896 var preset = _mainPresetIndex.match(entity, context.graph());
84897 name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
84901 this.innerText = name;
84904 }); // Don't hide entities related to this error - #5880
84906 context.features().forceVisible(relatedEntities);
84907 context.map().pan([0, 0]); // trigger a redraw
84910 improveOsmDetails.issue = function (val) {
84911 if (!arguments.length) return _qaItem;
84913 return improveOsmDetails;
84916 return improveOsmDetails;
84919 function uiImproveOsmHeader() {
84922 function issueTitle(d) {
84923 var issueKey = d.issueKey;
84924 d.replacements = d.replacements || {};
84925 d.replacements["default"] = _t.html('inspector.unknown'); // special key `default` works as a fallback string
84927 return _t.html("QA.improveOSM.error_types.".concat(issueKey, ".title"), d.replacements);
84930 function improveOsmHeader(selection) {
84931 var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
84932 return "".concat(d.id, "-").concat(d.status || 0);
84934 header.exit().remove();
84935 var headerEnter = header.enter().append('div').attr('class', 'qa-header');
84936 var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
84938 }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
84939 return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
84941 svgEnter.append('polygon').attr('fill', 'currentColor').attr('class', 'qaItem-fill').attr('points', '16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6');
84942 svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
84943 var picon = d.icon;
84948 var isMaki = /^maki-/.test(picon);
84949 return "#".concat(picon).concat(isMaki ? '-11' : '');
84952 headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
84955 improveOsmHeader.issue = function (val) {
84956 if (!arguments.length) return _qaItem;
84958 return improveOsmHeader;
84961 return improveOsmHeader;
84964 function uiImproveOsmEditor(context) {
84965 var dispatch = dispatch$8('change');
84966 var qaDetails = uiImproveOsmDetails(context);
84967 var qaComments = uiImproveOsmComments();
84968 var qaHeader = uiImproveOsmHeader();
84972 function improveOsmEditor(selection) {
84973 var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
84974 headerEnter.append('button').attr('class', 'close').on('click', function () {
84975 return context.enter(modeBrowse(context));
84976 }).call(svgIcon('#iD-icon-close'));
84977 headerEnter.append('h3').html(_t.html('QA.improveOSM.title'));
84978 var body = selection.selectAll('.body').data([0]);
84979 body = body.enter().append('div').attr('class', 'body').merge(body);
84980 var editor = body.selectAll('.qa-editor').data([0]);
84981 editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(qaComments.issue(_qaItem)).call(improveOsmSaveSection);
84984 function improveOsmSaveSection(selection) {
84985 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
84987 var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
84988 var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
84989 return "".concat(d.id, "-").concat(d.status || 0);
84992 saveSection.exit().remove(); // enter
84994 var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
84995 saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('note.newComment'));
84996 saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
84997 return d.newComment;
84998 }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
85000 saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85002 function changeInput() {
85003 var input = select(this);
85004 var val = input.property('value').trim();
85008 } // store the unsaved comment with the issue itself
85011 _qaItem = _qaItem.update({
85014 var qaService = services.improveOSM;
85017 qaService.replaceItem(_qaItem);
85020 saveSection.call(qaSaveButtons);
85024 function qaSaveButtons(selection) {
85025 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85027 var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85028 return d.status + d.id;
85031 buttonSection.exit().remove(); // enter
85033 var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85034 buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
85035 buttonEnter.append('button').attr('class', 'button close-button action');
85036 buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85038 buttonSection = buttonSection.merge(buttonEnter);
85039 buttonSection.select('.comment-button').attr('disabled', function (d) {
85040 return d.newComment ? null : true;
85041 }).on('click.comment', function (d3_event, d) {
85042 this.blur(); // avoid keeping focus on the button - #4641
85044 var qaService = services.improveOSM;
85047 qaService.postUpdate(d, function (err, item) {
85048 return dispatch.call('change', item);
85052 buttonSection.select('.close-button').html(function (d) {
85053 var andComment = d.newComment ? '_comment' : '';
85054 return _t.html("QA.keepRight.close".concat(andComment));
85055 }).on('click.close', function (d3_event, d) {
85056 this.blur(); // avoid keeping focus on the button - #4641
85058 var qaService = services.improveOSM;
85061 d.newStatus = 'SOLVED';
85062 qaService.postUpdate(d, function (err, item) {
85063 return dispatch.call('change', item);
85067 buttonSection.select('.ignore-button').html(function (d) {
85068 var andComment = d.newComment ? '_comment' : '';
85069 return _t.html("QA.keepRight.ignore".concat(andComment));
85070 }).on('click.ignore', function (d3_event, d) {
85071 this.blur(); // avoid keeping focus on the button - #4641
85073 var qaService = services.improveOSM;
85076 d.newStatus = 'INVALID';
85077 qaService.postUpdate(d, function (err, item) {
85078 return dispatch.call('change', item);
85082 } // NOTE: Don't change method name until UI v3 is merged
85085 improveOsmEditor.error = function (val) {
85086 if (!arguments.length) return _qaItem;
85088 return improveOsmEditor;
85091 return utilRebind(improveOsmEditor, dispatch, 'on');
85094 function uiKeepRightDetails(context) {
85097 function issueDetail(d) {
85098 var itemType = d.itemType,
85099 parentIssueType = d.parentIssueType;
85100 var unknown = _t.html('inspector.unknown');
85101 var replacements = d.replacements || {};
85102 replacements["default"] = unknown; // special key `default` works as a fallback string
85104 var detail = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".description"), replacements);
85106 if (detail === unknown) {
85107 detail = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".description"), replacements);
85113 function keepRightDetails(selection) {
85114 var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
85115 return "".concat(d.id, "-").concat(d.status || 0);
85117 details.exit().remove();
85118 var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // description
85120 var descriptionEnter = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85121 descriptionEnter.append('h4').html(_t.html('QA.keepRight.detail_description'));
85122 descriptionEnter.append('div').attr('class', 'qa-details-description-text').html(issueDetail); // If there are entity links in the error message..
85124 var relatedEntities = [];
85125 descriptionEnter.selectAll('.error_entity_link, .error_object_link').attr('href', '#').each(function () {
85126 var link = select(this);
85127 var isObjectLink = link.classed('error_object_link');
85128 var entityID = isObjectLink ? utilEntityRoot(_qaItem.objectType) + _qaItem.objectId : this.textContent;
85129 var entity = context.hasEntity(entityID);
85130 relatedEntities.push(entityID); // Add click handler
85132 link.on('mouseenter', function () {
85133 utilHighlightEntities([entityID], true, context);
85134 }).on('mouseleave', function () {
85135 utilHighlightEntities([entityID], false, context);
85136 }).on('click', function (d3_event) {
85137 d3_event.preventDefault();
85138 utilHighlightEntities([entityID], false, context);
85139 var osmlayer = context.layers().layer('osm');
85141 if (!osmlayer.enabled()) {
85142 osmlayer.enabled(true);
85145 context.map().centerZoomEase(_qaItem.loc, 20);
85148 context.enter(modeSelect(context, [entityID]));
85150 context.loadEntity(entityID, function (err, result) {
85152 var entity = result.data.find(function (e) {
85153 return e.id === entityID;
85155 if (entity) context.enter(modeSelect(context, [entityID]));
85158 }); // Replace with friendly name if possible
85159 // (The entity may not yet be loaded into the graph)
85162 var name = utilDisplayName(entity); // try to use common name
85164 if (!name && !isObjectLink) {
85165 var preset = _mainPresetIndex.match(entity, context.graph());
85166 name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
85170 this.innerText = name;
85173 }); // Don't hide entities related to this issue - #5880
85175 context.features().forceVisible(relatedEntities);
85176 context.map().pan([0, 0]); // trigger a redraw
85179 keepRightDetails.issue = function (val) {
85180 if (!arguments.length) return _qaItem;
85182 return keepRightDetails;
85185 return keepRightDetails;
85188 function uiKeepRightHeader() {
85191 function issueTitle(d) {
85192 var itemType = d.itemType,
85193 parentIssueType = d.parentIssueType;
85194 var unknown = _t.html('inspector.unknown');
85195 var replacements = d.replacements || {};
85196 replacements["default"] = unknown; // special key `default` works as a fallback string
85198 var title = _t.html("QA.keepRight.errorTypes.".concat(itemType, ".title"), replacements);
85200 if (title === unknown) {
85201 title = _t.html("QA.keepRight.errorTypes.".concat(parentIssueType, ".title"), replacements);
85207 function keepRightHeader(selection) {
85208 var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
85209 return "".concat(d.id, "-").concat(d.status || 0);
85211 header.exit().remove();
85212 var headerEnter = header.enter().append('div').attr('class', 'qa-header');
85213 var iconEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
85216 iconEnter.append('div').attr('class', function (d) {
85217 return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.parentIssueType);
85218 }).call(svgIcon('#iD-icon-bolt', 'qaItem-fill'));
85219 headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
85222 keepRightHeader.issue = function (val) {
85223 if (!arguments.length) return _qaItem;
85225 return keepRightHeader;
85228 return keepRightHeader;
85231 function uiViewOnKeepRight() {
85234 function viewOnKeepRight(selection) {
85237 if (services.keepRight && _qaItem instanceof QAItem) {
85238 url = services.keepRight.issueURL(_qaItem);
85241 var link = selection.selectAll('.view-on-keepRight').data(url ? [url] : []); // exit
85243 link.exit().remove(); // enter
85245 var linkEnter = link.enter().append('a').attr('class', 'view-on-keepRight').attr('target', '_blank').attr('rel', 'noopener') // security measure
85246 .attr('href', function (d) {
85248 }).call(svgIcon('#iD-icon-out-link', 'inline'));
85249 linkEnter.append('span').html(_t.html('inspector.view_on_keepRight'));
85252 viewOnKeepRight.what = function (val) {
85253 if (!arguments.length) return _qaItem;
85255 return viewOnKeepRight;
85258 return viewOnKeepRight;
85261 function uiKeepRightEditor(context) {
85262 var dispatch = dispatch$8('change');
85263 var qaDetails = uiKeepRightDetails(context);
85264 var qaHeader = uiKeepRightHeader();
85268 function keepRightEditor(selection) {
85269 var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
85270 headerEnter.append('button').attr('class', 'close').on('click', function () {
85271 return context.enter(modeBrowse(context));
85272 }).call(svgIcon('#iD-icon-close'));
85273 headerEnter.append('h3').html(_t.html('QA.keepRight.title'));
85274 var body = selection.selectAll('.body').data([0]);
85275 body = body.enter().append('div').attr('class', 'body').merge(body);
85276 var editor = body.selectAll('.qa-editor').data([0]);
85277 editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(keepRightSaveSection);
85278 var footer = selection.selectAll('.footer').data([0]);
85279 footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnKeepRight().what(_qaItem));
85282 function keepRightSaveSection(selection) {
85283 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85285 var isShown = _qaItem && (isSelected || _qaItem.newComment || _qaItem.comment);
85286 var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
85287 return "".concat(d.id, "-").concat(d.status || 0);
85290 saveSection.exit().remove(); // enter
85292 var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf');
85293 saveSectionEnter.append('h4').attr('class', '.qa-save-header').html(_t.html('QA.keepRight.comment'));
85294 saveSectionEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('QA.keepRight.comment_placeholder')).attr('maxlength', 1000).property('value', function (d) {
85295 return d.newComment || d.comment;
85296 }).call(utilNoAuto).on('input', changeInput).on('blur', changeInput); // update
85298 saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85300 function changeInput() {
85301 var input = select(this);
85302 var val = input.property('value').trim();
85304 if (val === _qaItem.comment) {
85306 } // store the unsaved comment with the issue itself
85309 _qaItem = _qaItem.update({
85312 var qaService = services.keepRight;
85315 qaService.replaceItem(_qaItem); // update keepright cache
85318 saveSection.call(qaSaveButtons);
85322 function qaSaveButtons(selection) {
85323 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85325 var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85326 return d.status + d.id;
85329 buttonSection.exit().remove(); // enter
85331 var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85332 buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('QA.keepRight.save_comment'));
85333 buttonEnter.append('button').attr('class', 'button close-button action');
85334 buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85336 buttonSection = buttonSection.merge(buttonEnter);
85337 buttonSection.select('.comment-button') // select and propagate data
85338 .attr('disabled', function (d) {
85339 return d.newComment ? null : true;
85340 }).on('click.comment', function (d3_event, d) {
85341 this.blur(); // avoid keeping focus on the button - #4641
85343 var qaService = services.keepRight;
85346 qaService.postUpdate(d, function (err, item) {
85347 return dispatch.call('change', item);
85351 buttonSection.select('.close-button') // select and propagate data
85352 .html(function (d) {
85353 var andComment = d.newComment ? '_comment' : '';
85354 return _t.html("QA.keepRight.close".concat(andComment));
85355 }).on('click.close', function (d3_event, d) {
85356 this.blur(); // avoid keeping focus on the button - #4641
85358 var qaService = services.keepRight;
85361 d.newStatus = 'ignore_t'; // ignore temporarily (item fixed)
85363 qaService.postUpdate(d, function (err, item) {
85364 return dispatch.call('change', item);
85368 buttonSection.select('.ignore-button') // select and propagate data
85369 .html(function (d) {
85370 var andComment = d.newComment ? '_comment' : '';
85371 return _t.html("QA.keepRight.ignore".concat(andComment));
85372 }).on('click.ignore', function (d3_event, d) {
85373 this.blur(); // avoid keeping focus on the button - #4641
85375 var qaService = services.keepRight;
85378 d.newStatus = 'ignore'; // ignore permanently (false positive)
85380 qaService.postUpdate(d, function (err, item) {
85381 return dispatch.call('change', item);
85385 } // NOTE: Don't change method name until UI v3 is merged
85388 keepRightEditor.error = function (val) {
85389 if (!arguments.length) return _qaItem;
85391 return keepRightEditor;
85394 return utilRebind(keepRightEditor, dispatch, 'on');
85397 function uiOsmoseDetails(context) {
85400 function issueString(d, type) {
85401 if (!d) return ''; // Issue strings are cached from Osmose API
85403 var s = services.osmose.getStrings(d.itemType);
85404 return type in s ? s[type] : '';
85407 function osmoseDetails(selection) {
85408 var details = selection.selectAll('.error-details').data(_qaItem ? [_qaItem] : [], function (d) {
85409 return "".concat(d.id, "-").concat(d.status || 0);
85411 details.exit().remove();
85412 var detailsEnter = details.enter().append('div').attr('class', 'error-details qa-details-container'); // Description
85414 if (issueString(_qaItem, 'detail')) {
85415 var div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85416 div.append('h4').html(_t.html('QA.keepRight.detail_description'));
85417 div.append('p').attr('class', 'qa-details-description-text').html(function (d) {
85418 return issueString(d, 'detail');
85419 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85420 } // Elements (populated later as data is requested)
85423 var detailsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85424 var elemsDiv = detailsEnter.append('div').attr('class', 'qa-details-subsection'); // Suggested Fix (mustn't exist for every issue type)
85426 if (issueString(_qaItem, 'fix')) {
85427 var _div = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85429 _div.append('h4').html(_t.html('QA.osmose.fix_title'));
85431 _div.append('p').html(function (d) {
85432 return issueString(d, 'fix');
85433 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85434 } // Common Pitfalls (mustn't exist for every issue type)
85437 if (issueString(_qaItem, 'trap')) {
85438 var _div2 = detailsEnter.append('div').attr('class', 'qa-details-subsection');
85440 _div2.append('h4').html(_t.html('QA.osmose.trap_title'));
85442 _div2.append('p').html(function (d) {
85443 return issueString(d, 'trap');
85444 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85445 } // Save current item to check if UI changed by time request resolves
85448 var thisItem = _qaItem;
85449 services.osmose.loadIssueDetail(_qaItem).then(function (d) {
85450 // No details to add if there are no associated issue elements
85451 if (!d.elems || d.elems.length === 0) return; // Do nothing if UI has moved on by the time this resolves
85453 if (context.selectedErrorID() !== thisItem.id && context.container().selectAll(".qaItem.osmose.hover.itemId-".concat(thisItem.id)).empty()) return; // Things like keys and values are dynamically added to a subtitle string
85456 detailsDiv.append('h4').html(_t.html('QA.osmose.detail_title'));
85457 detailsDiv.append('p').html(function (d) {
85459 }).selectAll('a').attr('rel', 'noopener').attr('target', '_blank');
85460 } // Create list of linked issue elements
85463 elemsDiv.append('h4').html(_t.html('QA.osmose.elems_title'));
85464 elemsDiv.append('ul').selectAll('li').data(d.elems).enter().append('li').append('a').attr('href', '#').attr('class', 'error_entity_link').html(function (d) {
85466 }).each(function () {
85467 var link = select(this);
85468 var entityID = this.textContent;
85469 var entity = context.hasEntity(entityID); // Add click handler
85471 link.on('mouseenter', function () {
85472 utilHighlightEntities([entityID], true, context);
85473 }).on('mouseleave', function () {
85474 utilHighlightEntities([entityID], false, context);
85475 }).on('click', function (d3_event) {
85476 d3_event.preventDefault();
85477 utilHighlightEntities([entityID], false, context);
85478 var osmlayer = context.layers().layer('osm');
85480 if (!osmlayer.enabled()) {
85481 osmlayer.enabled(true);
85484 context.map().centerZoom(d.loc, 20);
85487 context.enter(modeSelect(context, [entityID]));
85489 context.loadEntity(entityID, function (err, result) {
85491 var entity = result.data.find(function (e) {
85492 return e.id === entityID;
85494 if (entity) context.enter(modeSelect(context, [entityID]));
85497 }); // Replace with friendly name if possible
85498 // (The entity may not yet be loaded into the graph)
85501 var name = utilDisplayName(entity); // try to use common name
85504 var preset = _mainPresetIndex.match(entity, context.graph());
85505 name = preset && !preset.isFallback() && preset.name(); // fallback to preset name
85509 this.innerText = name;
85512 }); // Don't hide entities related to this issue - #5880
85514 context.features().forceVisible(d.elems);
85515 context.map().pan([0, 0]); // trigger a redraw
85516 })["catch"](function (err) {
85517 console.log(err); // eslint-disable-line no-console
85521 osmoseDetails.issue = function (val) {
85522 if (!arguments.length) return _qaItem;
85524 return osmoseDetails;
85527 return osmoseDetails;
85530 function uiOsmoseHeader() {
85533 function issueTitle(d) {
85534 var unknown = _t('inspector.unknown');
85535 if (!d) return unknown; // Issue titles supplied by Osmose
85537 var s = services.osmose.getStrings(d.itemType);
85538 return 'title' in s ? s.title : unknown;
85541 function osmoseHeader(selection) {
85542 var header = selection.selectAll('.qa-header').data(_qaItem ? [_qaItem] : [], function (d) {
85543 return "".concat(d.id, "-").concat(d.status || 0);
85545 header.exit().remove();
85546 var headerEnter = header.enter().append('div').attr('class', 'qa-header');
85547 var svgEnter = headerEnter.append('div').attr('class', 'qa-header-icon').classed('new', function (d) {
85549 }).append('svg').attr('width', '20px').attr('height', '30px').attr('viewbox', '0 0 20 30').attr('class', function (d) {
85550 return "preset-icon-28 qaItem ".concat(d.service, " itemId-").concat(d.id, " itemType-").concat(d.itemType);
85552 svgEnter.append('polygon').attr('fill', function (d) {
85553 return services.osmose.getColor(d.item);
85554 }).attr('class', 'qaItem-fill').attr('points', '16,3 4,3 1,6 1,17 4,20 7,20 10,27 13,20 16,20 19,17.033 19,6');
85555 svgEnter.append('use').attr('class', 'icon-annotation').attr('width', '13px').attr('height', '13px').attr('transform', 'translate(3.5, 5)').attr('xlink:href', function (d) {
85556 var picon = d.icon;
85561 var isMaki = /^maki-/.test(picon);
85562 return "#".concat(picon).concat(isMaki ? '-11' : '');
85565 headerEnter.append('div').attr('class', 'qa-header-label').html(issueTitle);
85568 osmoseHeader.issue = function (val) {
85569 if (!arguments.length) return _qaItem;
85571 return osmoseHeader;
85574 return osmoseHeader;
85577 function uiViewOnOsmose() {
85580 function viewOnOsmose(selection) {
85583 if (services.osmose && _qaItem instanceof QAItem) {
85584 url = services.osmose.itemURL(_qaItem);
85587 var link = selection.selectAll('.view-on-osmose').data(url ? [url] : []); // exit
85589 link.exit().remove(); // enter
85591 var linkEnter = link.enter().append('a').attr('class', 'view-on-osmose').attr('target', '_blank').attr('rel', 'noopener') // security measure
85592 .attr('href', function (d) {
85594 }).call(svgIcon('#iD-icon-out-link', 'inline'));
85595 linkEnter.append('span').html(_t.html('inspector.view_on_osmose'));
85598 viewOnOsmose.what = function (val) {
85599 if (!arguments.length) return _qaItem;
85601 return viewOnOsmose;
85604 return viewOnOsmose;
85607 function uiOsmoseEditor(context) {
85608 var dispatch = dispatch$8('change');
85609 var qaDetails = uiOsmoseDetails(context);
85610 var qaHeader = uiOsmoseHeader();
85614 function osmoseEditor(selection) {
85615 var header = selection.selectAll('.header').data([0]);
85616 var headerEnter = header.enter().append('div').attr('class', 'header fillL');
85617 headerEnter.append('button').attr('class', 'close').on('click', function () {
85618 return context.enter(modeBrowse(context));
85619 }).call(svgIcon('#iD-icon-close'));
85620 headerEnter.append('h3').html(_t.html('QA.osmose.title'));
85621 var body = selection.selectAll('.body').data([0]);
85622 body = body.enter().append('div').attr('class', 'body').merge(body);
85623 var editor = body.selectAll('.qa-editor').data([0]);
85624 editor.enter().append('div').attr('class', 'modal-section qa-editor').merge(editor).call(qaHeader.issue(_qaItem)).call(qaDetails.issue(_qaItem)).call(osmoseSaveSection);
85625 var footer = selection.selectAll('.footer').data([0]);
85626 footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOsmose().what(_qaItem));
85629 function osmoseSaveSection(selection) {
85630 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85632 var isShown = _qaItem && isSelected;
85633 var saveSection = selection.selectAll('.qa-save').data(isShown ? [_qaItem] : [], function (d) {
85634 return "".concat(d.id, "-").concat(d.status || 0);
85637 saveSection.exit().remove(); // enter
85639 var saveSectionEnter = saveSection.enter().append('div').attr('class', 'qa-save save-section cf'); // update
85641 saveSection = saveSectionEnter.merge(saveSection).call(qaSaveButtons);
85644 function qaSaveButtons(selection) {
85645 var isSelected = _qaItem && _qaItem.id === context.selectedErrorID();
85647 var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_qaItem] : [], function (d) {
85648 return d.status + d.id;
85651 buttonSection.exit().remove(); // enter
85653 var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
85654 buttonEnter.append('button').attr('class', 'button close-button action');
85655 buttonEnter.append('button').attr('class', 'button ignore-button action'); // update
85657 buttonSection = buttonSection.merge(buttonEnter);
85658 buttonSection.select('.close-button').html(_t.html('QA.keepRight.close')).on('click.close', function (d3_event, d) {
85659 this.blur(); // avoid keeping focus on the button - #4641
85661 var qaService = services.osmose;
85664 d.newStatus = 'done';
85665 qaService.postUpdate(d, function (err, item) {
85666 return dispatch.call('change', item);
85670 buttonSection.select('.ignore-button').html(_t.html('QA.keepRight.ignore')).on('click.ignore', function (d3_event, d) {
85671 this.blur(); // avoid keeping focus on the button - #4641
85673 var qaService = services.osmose;
85676 d.newStatus = 'false';
85677 qaService.postUpdate(d, function (err, item) {
85678 return dispatch.call('change', item);
85682 } // NOTE: Don't change method name until UI v3 is merged
85685 osmoseEditor.error = function (val) {
85686 if (!arguments.length) return _qaItem;
85688 return osmoseEditor;
85691 return utilRebind(osmoseEditor, dispatch, 'on');
85694 function uiNoteComments() {
85697 function noteComments(selection) {
85698 if (_note.isNew()) return; // don't draw .comments-container
85700 var comments = selection.selectAll('.comments-container').data([0]);
85701 comments = comments.enter().append('div').attr('class', 'comments-container').merge(comments);
85702 var commentEnter = comments.selectAll('.comment').data(_note.comments).enter().append('div').attr('class', 'comment');
85703 commentEnter.append('div').attr('class', function (d) {
85704 return 'comment-avatar user-' + d.uid;
85705 }).call(svgIcon('#iD-icon-avatar', 'comment-avatar-icon'));
85706 var mainEnter = commentEnter.append('div').attr('class', 'comment-main');
85707 var metadataEnter = mainEnter.append('div').attr('class', 'comment-metadata');
85708 metadataEnter.append('div').attr('class', 'comment-author').each(function (d) {
85709 var selection = select(this);
85710 var osm = services.osm;
85712 if (osm && d.user) {
85713 selection = selection.append('a').attr('class', 'comment-author-link').attr('href', osm.userURL(d.user)).attr('target', '_blank');
85716 selection.html(function (d) {
85717 return d.user || _t.html('note.anonymous');
85720 metadataEnter.append('div').attr('class', 'comment-date').html(function (d) {
85721 return _t('note.status.' + d.action, {
85722 when: localeDateString(d.date)
85725 mainEnter.append('div').attr('class', 'comment-text').html(function (d) {
85727 }).selectAll('a').attr('rel', 'noopener nofollow').attr('target', '_blank');
85728 comments.call(replaceAvatars);
85731 function replaceAvatars(selection) {
85732 var showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
85733 var osm = services.osm;
85734 if (showThirdPartyIcons !== 'true' || !osm) return;
85735 var uids = {}; // gather uids in the comment thread
85737 _note.comments.forEach(function (d) {
85738 if (d.uid) uids[d.uid] = true;
85741 Object.keys(uids).forEach(function (uid) {
85742 osm.loadUser(uid, function (err, user) {
85743 if (!user || !user.image_url) return;
85744 selection.selectAll('.comment-avatar.user-' + uid).html('').append('img').attr('class', 'icon comment-avatar-icon').attr('src', user.image_url).attr('alt', user.display_name);
85749 function localeDateString(s) {
85750 if (!s) return null;
85756 s = s.replace(/-/g, '/'); // fix browser-specific Date() issues
85758 var d = new Date(s);
85759 if (isNaN(d.getTime())) return null;
85760 return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
85763 noteComments.note = function (val) {
85764 if (!arguments.length) return _note;
85766 return noteComments;
85769 return noteComments;
85772 function uiNoteHeader() {
85775 function noteHeader(selection) {
85776 var header = selection.selectAll('.note-header').data(_note ? [_note] : [], function (d) {
85777 return d.status + d.id;
85779 header.exit().remove();
85780 var headerEnter = header.enter().append('div').attr('class', 'note-header');
85781 var iconEnter = headerEnter.append('div').attr('class', function (d) {
85782 return 'note-header-icon ' + d.status;
85783 }).classed('new', function (d) {
85786 iconEnter.append('div').attr('class', 'preset-icon-28').call(svgIcon('#iD-icon-note', 'note-fill'));
85787 iconEnter.each(function (d) {
85791 statusIcon = '#iD-icon-plus';
85792 } else if (d.status === 'open') {
85793 statusIcon = '#iD-icon-close';
85795 statusIcon = '#iD-icon-apply';
85798 iconEnter.append('div').attr('class', 'note-icon-annotation').call(svgIcon(statusIcon, 'icon-annotation'));
85800 headerEnter.append('div').attr('class', 'note-header-label').html(function (d) {
85801 if (_note.isNew()) {
85802 return _t('note.new');
85805 return _t('note.note') + ' ' + d.id + ' ' + (d.status === 'closed' ? _t('note.closed') : '');
85809 noteHeader.note = function (val) {
85810 if (!arguments.length) return _note;
85818 function uiNoteReport() {
85821 function noteReport(selection) {
85824 if (services.osm && _note instanceof osmNote && !_note.isNew()) {
85825 url = services.osm.noteReportURL(_note);
85828 var link = selection.selectAll('.note-report').data(url ? [url] : []); // exit
85830 link.exit().remove(); // enter
85832 var linkEnter = link.enter().append('a').attr('class', 'note-report').attr('target', '_blank').attr('href', function (d) {
85834 }).call(svgIcon('#iD-icon-out-link', 'inline'));
85835 linkEnter.append('span').html(_t.html('note.report'));
85838 noteReport.note = function (val) {
85839 if (!arguments.length) return _note;
85847 function uiNoteEditor(context) {
85848 var dispatch = dispatch$8('change');
85849 var noteComments = uiNoteComments();
85850 var noteHeader = uiNoteHeader(); // var formFields = uiFormFields(context);
85854 var _newNote; // var _fieldsArr;
85857 function noteEditor(selection) {
85858 var header = selection.selectAll('.header').data([0]);
85859 var headerEnter = header.enter().append('div').attr('class', 'header fillL');
85860 headerEnter.append('button').attr('class', 'close').on('click', function () {
85861 context.enter(modeBrowse(context));
85862 }).call(svgIcon('#iD-icon-close'));
85863 headerEnter.append('h3').html(_t.html('note.title'));
85864 var body = selection.selectAll('.body').data([0]);
85865 body = body.enter().append('div').attr('class', 'body').merge(body);
85866 var editor = body.selectAll('.note-editor').data([0]);
85867 editor.enter().append('div').attr('class', 'modal-section note-editor').merge(editor).call(noteHeader.note(_note)).call(noteComments.note(_note)).call(noteSaveSection);
85868 var footer = selection.selectAll('.footer').data([0]);
85869 footer.enter().append('div').attr('class', 'footer').merge(footer).call(uiViewOnOSM(context).what(_note)).call(uiNoteReport().note(_note)); // rerender the note editor on any auth change
85871 var osm = services.osm;
85874 osm.on('change.note-save', function () {
85875 selection.call(noteEditor);
85880 function noteSaveSection(selection) {
85881 var isSelected = _note && _note.id === context.selectedNoteID();
85883 var noteSave = selection.selectAll('.note-save').data(isSelected ? [_note] : [], function (d) {
85884 return d.status + d.id;
85887 noteSave.exit().remove(); // enter
85889 var noteSaveEnter = noteSave.enter().append('div').attr('class', 'note-save save-section cf'); // // if new note, show categories to pick from
85890 // if (_note.isNew()) {
85891 // var presets = presetManager;
85892 // // NOTE: this key isn't a age and therefore there is no documentation (yet)
85894 // uiField(context, presets.field('category'), null, { show: true, revert: false }),
85896 // _fieldsArr.forEach(function(field) {
85898 // .on('change', changeCategory);
85902 // .attr('class', 'note-category')
85903 // .call(formFields.fieldsArr(_fieldsArr));
85905 // function changeCategory() {
85906 // // NOTE: perhaps there is a better way to get value
85907 // var val = context.container().select('input[name=\'category\']:checked').property('__data__') || undefined;
85908 // // store the unsaved category with the note itself
85909 // _note = _note.update({ newCategory: val });
85910 // var osm = services.osm;
85912 // osm.replaceNote(_note); // update note cache
85915 // .call(noteSaveButtons);
85918 noteSaveEnter.append('h4').attr('class', '.note-save-header').html(function () {
85919 return _note.isNew() ? _t('note.newDescription') : _t('note.newComment');
85921 var commentTextarea = noteSaveEnter.append('textarea').attr('class', 'new-comment-input').attr('placeholder', _t('note.inputPlaceholder')).attr('maxlength', 1000).property('value', function (d) {
85922 return d.newComment;
85923 }).call(utilNoAuto).on('keydown.note-input', keydown).on('input.note-input', changeInput).on('blur.note-input', changeInput);
85925 if (!commentTextarea.empty() && _newNote) {
85926 // autofocus the comment field for new notes
85927 commentTextarea.node().focus();
85931 noteSave = noteSaveEnter.merge(noteSave).call(userDetails).call(noteSaveButtons); // fast submit if user presses cmd+enter
85933 function keydown(d3_event) {
85934 if (!(d3_event.keyCode === 13 && // ↩ Return
85935 d3_event.metaKey)) return;
85936 var osm = services.osm;
85938 var hasAuth = osm.authenticated();
85939 if (!hasAuth) return;
85940 if (!_note.newComment) return;
85941 d3_event.preventDefault();
85942 select(this).on('keydown.note-input', null); // focus on button and submit
85944 window.setTimeout(function () {
85945 if (_note.isNew()) {
85946 noteSave.selectAll('.save-button').node().focus();
85949 noteSave.selectAll('.comment-button').node().focus();
85955 function changeInput() {
85956 var input = select(this);
85957 var val = input.property('value').trim() || undefined; // store the unsaved comment with the note itself
85959 _note = _note.update({
85962 var osm = services.osm;
85965 osm.replaceNote(_note); // update note cache
85968 noteSave.call(noteSaveButtons);
85972 function userDetails(selection) {
85973 var detailSection = selection.selectAll('.detail-section').data([0]);
85974 detailSection = detailSection.enter().append('div').attr('class', 'detail-section').merge(detailSection);
85975 var osm = services.osm;
85976 if (!osm) return; // Add warning if user is not logged in
85978 var hasAuth = osm.authenticated();
85979 var authWarning = detailSection.selectAll('.auth-warning').data(hasAuth ? [] : [0]);
85980 authWarning.exit().transition().duration(200).style('opacity', 0).remove();
85981 var authEnter = authWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning auth-warning').style('opacity', 0);
85982 authEnter.call(svgIcon('#iD-icon-alert', 'inline'));
85983 authEnter.append('span').html(_t.html('note.login'));
85984 authEnter.append('a').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html('login')).on('click.note-login', function (d3_event) {
85985 d3_event.preventDefault();
85986 osm.authenticate();
85988 authEnter.transition().duration(200).style('opacity', 1);
85989 var prose = detailSection.selectAll('.note-save-prose').data(hasAuth ? [0] : []);
85990 prose.exit().remove();
85991 prose = prose.enter().append('p').attr('class', 'note-save-prose').html(_t.html('note.upload_explanation')).merge(prose);
85992 osm.userDetails(function (err, user) {
85994 var userLink = select(document.createElement('div'));
85996 if (user.image_url) {
85997 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
86000 userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
86001 prose.html(_t.html('note.upload_explanation_with_user', {
86002 user: userLink.html()
86007 function noteSaveButtons(selection) {
86008 var osm = services.osm;
86009 var hasAuth = osm && osm.authenticated();
86011 var isSelected = _note && _note.id === context.selectedNoteID();
86013 var buttonSection = selection.selectAll('.buttons').data(isSelected ? [_note] : [], function (d) {
86014 return d.status + d.id;
86017 buttonSection.exit().remove(); // enter
86019 var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons');
86021 if (_note.isNew()) {
86022 buttonEnter.append('button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
86023 buttonEnter.append('button').attr('class', 'button save-button action').html(_t.html('note.save'));
86025 buttonEnter.append('button').attr('class', 'button status-button action');
86026 buttonEnter.append('button').attr('class', 'button comment-button action').html(_t.html('note.comment'));
86030 buttonSection = buttonSection.merge(buttonEnter);
86031 buttonSection.select('.cancel-button') // select and propagate data
86032 .on('click.cancel', clickCancel);
86033 buttonSection.select('.save-button') // select and propagate data
86034 .attr('disabled', isSaveDisabled).on('click.save', clickSave);
86035 buttonSection.select('.status-button') // select and propagate data
86036 .attr('disabled', hasAuth ? null : true).html(function (d) {
86037 var action = d.status === 'open' ? 'close' : 'open';
86038 var andComment = d.newComment ? '_comment' : '';
86039 return _t('note.' + action + andComment);
86040 }).on('click.status', clickStatus);
86041 buttonSection.select('.comment-button') // select and propagate data
86042 .attr('disabled', isSaveDisabled).on('click.comment', clickComment);
86044 function isSaveDisabled(d) {
86045 return hasAuth && d.status === 'open' && d.newComment ? null : true;
86049 function clickCancel(d3_event, d) {
86050 this.blur(); // avoid keeping focus on the button - #4641
86052 var osm = services.osm;
86058 context.enter(modeBrowse(context));
86059 dispatch.call('change');
86062 function clickSave(d3_event, d) {
86063 this.blur(); // avoid keeping focus on the button - #4641
86065 var osm = services.osm;
86068 osm.postNoteCreate(d, function (err, note) {
86069 dispatch.call('change', note);
86074 function clickStatus(d3_event, d) {
86075 this.blur(); // avoid keeping focus on the button - #4641
86077 var osm = services.osm;
86080 var setStatus = d.status === 'open' ? 'closed' : 'open';
86081 osm.postNoteUpdate(d, setStatus, function (err, note) {
86082 dispatch.call('change', note);
86087 function clickComment(d3_event, d) {
86088 this.blur(); // avoid keeping focus on the button - #4641
86090 var osm = services.osm;
86093 osm.postNoteUpdate(d, d.status, function (err, note) {
86094 dispatch.call('change', note);
86099 noteEditor.note = function (val) {
86100 if (!arguments.length) return _note;
86105 noteEditor.newNote = function (val) {
86106 if (!arguments.length) return _newNote;
86111 return utilRebind(noteEditor, dispatch, 'on');
86114 function uiSidebar(context) {
86115 var inspector = uiInspector(context);
86116 var dataEditor = uiDataEditor(context);
86117 var noteEditor = uiNoteEditor(context);
86118 var improveOsmEditor = uiImproveOsmEditor(context);
86119 var keepRightEditor = uiKeepRightEditor(context);
86120 var osmoseEditor = uiOsmoseEditor(context);
86124 var _wasData = false;
86125 var _wasNote = false;
86126 var _wasQaItem = false; // use pointer events on supported platforms; fallback to mouse events
86128 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
86130 function sidebar(selection) {
86131 var container = context.container();
86132 var minWidth = 240;
86134 var containerWidth;
86135 var dragOffset; // Set the initial width constraints
86137 selection.style('min-width', minWidth + 'px').style('max-width', '400px').style('width', '33.3333%');
86138 var resizer = selection.append('div').attr('class', 'sidebar-resizer').on(_pointerPrefix + 'down.sidebar-resizer', pointerdown);
86139 var downPointerId, lastClientX, containerLocGetter;
86141 function pointerdown(d3_event) {
86142 if (downPointerId) return;
86143 if ('button' in d3_event && d3_event.button !== 0) return;
86144 downPointerId = d3_event.pointerId || 'mouse';
86145 lastClientX = d3_event.clientX;
86146 containerLocGetter = utilFastMouse(container.node()); // offset from edge of sidebar-resizer
86148 dragOffset = utilFastMouse(resizer.node())(d3_event)[0] - 1;
86149 sidebarWidth = selection.node().getBoundingClientRect().width;
86150 containerWidth = container.node().getBoundingClientRect().width;
86151 var widthPct = sidebarWidth / containerWidth * 100;
86152 selection.style('width', widthPct + '%') // lock in current width
86153 .style('max-width', '85%'); // but allow larger widths
86155 resizer.classed('dragging', true);
86156 select(window).on('touchmove.sidebar-resizer', function (d3_event) {
86157 // disable page scrolling while resizing on touch input
86158 d3_event.preventDefault();
86161 }).on(_pointerPrefix + 'move.sidebar-resizer', pointermove).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', pointerup);
86164 function pointermove(d3_event) {
86165 if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
86166 d3_event.preventDefault();
86167 var dx = d3_event.clientX - lastClientX;
86168 lastClientX = d3_event.clientX;
86169 var isRTL = _mainLocalizer.textDirection() === 'rtl';
86170 var scaleX = isRTL ? 0 : 1;
86171 var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
86172 var x = containerLocGetter(d3_event)[0] - dragOffset;
86173 sidebarWidth = isRTL ? containerWidth - x : x;
86174 var isCollapsed = selection.classed('collapsed');
86175 var shouldCollapse = sidebarWidth < minWidth;
86176 selection.classed('collapsed', shouldCollapse);
86178 if (shouldCollapse) {
86179 if (!isCollapsed) {
86180 selection.style(xMarginProperty, '-400px').style('width', '400px');
86181 context.ui().onResize([(sidebarWidth - dx) * scaleX, 0]);
86184 var widthPct = sidebarWidth / containerWidth * 100;
86185 selection.style(xMarginProperty, null).style('width', widthPct + '%');
86188 context.ui().onResize([-sidebarWidth * scaleX, 0]);
86190 context.ui().onResize([-dx * scaleX, 0]);
86195 function pointerup(d3_event) {
86196 if (downPointerId !== (d3_event.pointerId || 'mouse')) return;
86197 downPointerId = null;
86198 resizer.classed('dragging', false);
86199 select(window).on('touchmove.sidebar-resizer', null).on(_pointerPrefix + 'move.sidebar-resizer', null).on(_pointerPrefix + 'up.sidebar-resizer pointercancel.sidebar-resizer', null);
86202 var featureListWrap = selection.append('div').attr('class', 'feature-list-pane').call(uiFeatureList(context));
86203 var inspectorWrap = selection.append('div').attr('class', 'inspector-hidden inspector-wrap');
86205 var hoverModeSelect = function hoverModeSelect(targets) {
86206 context.container().selectAll('.feature-list-item button').classed('hover', false);
86208 if (context.selectedIDs().length > 1 && targets && targets.length) {
86209 var elements = context.container().selectAll('.feature-list-item button').filter(function (node) {
86210 return targets.indexOf(node) !== -1;
86213 if (!elements.empty()) {
86214 elements.classed('hover', true);
86219 sidebar.hoverModeSelect = throttle(hoverModeSelect, 200);
86221 function hover(targets) {
86222 var datum = targets && targets.length && targets[0];
86224 if (datum && datum.__featurehash__) {
86225 // hovering on data
86227 sidebar.show(dataEditor.datum(datum));
86228 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86229 } else if (datum instanceof osmNote) {
86230 if (context.mode().id === 'drag-note') return;
86232 var osm = services.osm;
86235 datum = osm.getNote(datum.id); // marker may contain stale data - get latest
86238 sidebar.show(noteEditor.note(datum));
86239 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86240 } else if (datum instanceof QAItem) {
86242 var errService = services[datum.service];
86245 // marker may contain stale data - get latest
86246 datum = errService.getError(datum.id);
86247 } // Currently only three possible services
86252 if (datum.service === 'keepRight') {
86253 errEditor = keepRightEditor;
86254 } else if (datum.service === 'osmose') {
86255 errEditor = osmoseEditor;
86257 errEditor = improveOsmEditor;
86260 context.container().selectAll('.qaItem.' + datum.service).classed('hover', function (d) {
86261 return d.id === datum.id;
86263 sidebar.show(errEditor.error(datum));
86264 selection.selectAll('.sidebar-component').classed('inspector-hover', true);
86265 } else if (!_current && datum instanceof osmEntity) {
86266 featureListWrap.classed('inspector-hidden', true);
86267 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', true);
86269 if (!inspector.entityIDs() || !utilArrayIdentical(inspector.entityIDs(), [datum.id]) || inspector.state() !== 'hover') {
86270 inspector.state('hover').entityIDs([datum.id]).newFeature(false);
86271 inspectorWrap.call(inspector);
86273 } else if (!_current) {
86274 featureListWrap.classed('inspector-hidden', false);
86275 inspectorWrap.classed('inspector-hidden', true);
86276 inspector.state('hide');
86277 } else if (_wasData || _wasNote || _wasQaItem) {
86280 _wasQaItem = false;
86281 context.container().selectAll('.note').classed('hover', false);
86282 context.container().selectAll('.qaItem').classed('hover', false);
86287 sidebar.hover = throttle(hover, 200);
86289 sidebar.intersects = function (extent) {
86290 var rect = selection.node().getBoundingClientRect();
86291 return extent.intersects([context.projection.invert([0, rect.height]), context.projection.invert([rect.width, 0])]);
86294 sidebar.select = function (ids, newFeature) {
86297 if (ids && ids.length) {
86298 var entity = ids.length === 1 && context.entity(ids[0]);
86300 if (entity && newFeature && selection.classed('collapsed')) {
86301 // uncollapse the sidebar
86302 var extent = entity.extent(context.graph());
86303 sidebar.expand(sidebar.intersects(extent));
86306 featureListWrap.classed('inspector-hidden', true);
86307 inspectorWrap.classed('inspector-hidden', false).classed('inspector-hover', false); // reload the UI even if the ids are the same since the entities
86308 // themselves may have changed
86310 inspector.state('select').entityIDs(ids).newFeature(newFeature);
86311 inspectorWrap.call(inspector);
86313 inspector.state('hide');
86317 sidebar.showPresetList = function () {
86318 inspector.showList();
86321 sidebar.show = function (component, element) {
86322 featureListWrap.classed('inspector-hidden', true);
86323 inspectorWrap.classed('inspector-hidden', true);
86324 if (_current) _current.remove();
86325 _current = selection.append('div').attr('class', 'sidebar-component').call(component, element);
86328 sidebar.hide = function () {
86329 featureListWrap.classed('inspector-hidden', false);
86330 inspectorWrap.classed('inspector-hidden', true);
86331 if (_current) _current.remove();
86335 sidebar.expand = function (moveMap) {
86336 if (selection.classed('collapsed')) {
86337 sidebar.toggle(moveMap);
86341 sidebar.collapse = function (moveMap) {
86342 if (!selection.classed('collapsed')) {
86343 sidebar.toggle(moveMap);
86347 sidebar.toggle = function (moveMap) {
86348 // Don't allow sidebar to toggle when the user is in the walkthrough.
86349 if (context.inIntro()) return;
86350 var isCollapsed = selection.classed('collapsed');
86351 var isCollapsing = !isCollapsed;
86352 var isRTL = _mainLocalizer.textDirection() === 'rtl';
86353 var scaleX = isRTL ? 0 : 1;
86354 var xMarginProperty = isRTL ? 'margin-right' : 'margin-left';
86355 sidebarWidth = selection.node().getBoundingClientRect().width; // switch from % to px
86357 selection.style('width', sidebarWidth + 'px');
86358 var startMargin, endMargin, lastMargin;
86360 if (isCollapsing) {
86361 startMargin = lastMargin = 0;
86362 endMargin = -sidebarWidth;
86364 startMargin = lastMargin = -sidebarWidth;
86368 if (!isCollapsing) {
86369 // unhide the sidebar's content before it transitions onscreen
86370 selection.classed('collapsed', isCollapsing);
86373 selection.transition().style(xMarginProperty, endMargin + 'px').tween('panner', function () {
86374 var i = d3_interpolateNumber(startMargin, endMargin);
86375 return function (t) {
86376 var dx = lastMargin - Math.round(i(t));
86377 lastMargin = lastMargin - dx;
86378 context.ui().onResize(moveMap ? undefined : [dx * scaleX, 0]);
86380 }).on('end', function () {
86381 if (isCollapsing) {
86382 // hide the sidebar's content after it transitions offscreen
86383 selection.classed('collapsed', isCollapsing);
86384 } // switch back from px to %
86387 if (!isCollapsing) {
86388 var containerWidth = container.node().getBoundingClientRect().width;
86389 var widthPct = sidebarWidth / containerWidth * 100;
86390 selection.style(xMarginProperty, null).style('width', widthPct + '%');
86393 }; // toggle the sidebar collapse when double-clicking the resizer
86396 resizer.on('dblclick', function (d3_event) {
86397 d3_event.preventDefault();
86399 if (d3_event.sourceEvent) {
86400 d3_event.sourceEvent.preventDefault();
86404 }); // ensure hover sidebar is closed when zooming out beyond editable zoom
86406 context.map().on('crossEditableZoom.sidebar', function (within) {
86407 if (!within && !selection.select('.inspector-hover').empty()) {
86413 sidebar.showPresetList = function () {};
86415 sidebar.hover = function () {};
86417 sidebar.hover.cancel = function () {};
86419 sidebar.intersects = function () {};
86421 sidebar.select = function () {};
86423 sidebar.show = function () {};
86425 sidebar.hide = function () {};
86427 sidebar.expand = function () {};
86429 sidebar.collapse = function () {};
86431 sidebar.toggle = function () {};
86436 function uiSourceSwitch(context) {
86439 function click(d3_event) {
86440 d3_event.preventDefault();
86441 var osm = context.connection();
86443 if (context.inIntro()) return;
86444 if (context.history().hasChanges() && !window.confirm(_t('source_switch.lose_changes'))) return;
86445 var isLive = select(this).classed('live');
86447 context.enter(modeBrowse(context));
86448 context.history().clearSaved(); // remove saved history
86450 context.flush(); // remove stored data
86452 select(this).html(isLive ? _t.html('source_switch.live') : _t.html('source_switch.dev')).classed('live', isLive).classed('chip', isLive);
86453 osm["switch"](isLive ? keys[0] : keys[1]); // switch connection (warning: dispatches 'change' event)
86456 var sourceSwitch = function sourceSwitch(selection) {
86457 selection.append('a').attr('href', '#').html(_t.html('source_switch.live')).attr('class', 'live chip').on('click', click);
86460 sourceSwitch.keys = function (_) {
86461 if (!arguments.length) return keys;
86463 return sourceSwitch;
86466 return sourceSwitch;
86469 function uiSpinner(context) {
86470 var osm = context.connection();
86471 return function (selection) {
86472 var img = selection.append('img').attr('src', context.imagePath('loader-black.gif')).style('opacity', 0);
86475 osm.on('loading.spinner', function () {
86476 img.transition().style('opacity', 1);
86477 }).on('loaded.spinner', function () {
86478 img.transition().style('opacity', 0);
86484 function uiSplash(context) {
86485 return function (selection) {
86486 // Exception - if there are restorable changes, skip this splash screen.
86487 // This is because we currently only support one `uiModal` at a time
86488 // and we need to show them `uiRestore`` instead of this one.
86489 if (context.history().hasRestorableChanges()) return; // If user has not seen this version of the privacy policy, show the splash again.
86491 var updateMessage = '';
86492 var sawPrivacyVersion = corePreferences('sawPrivacyVersion');
86493 var showSplash = !corePreferences('sawSplash');
86495 if (sawPrivacyVersion !== context.privacyVersion) {
86496 updateMessage = _t('splash.privacy_update');
86500 if (!showSplash) return;
86501 corePreferences('sawSplash', true);
86502 corePreferences('sawPrivacyVersion', context.privacyVersion); // fetch intro graph data now, while user is looking at the splash screen
86504 _mainFileFetcher.get('intro_graph');
86505 var modalSelection = uiModal(selection);
86506 modalSelection.select('.modal').attr('class', 'modal-splash modal');
86507 var introModal = modalSelection.select('.content').append('div').attr('class', 'fillL');
86508 introModal.append('div').attr('class', 'modal-section').append('h3').html(_t.html('splash.welcome'));
86509 var modalSection = introModal.append('div').attr('class', 'modal-section');
86510 modalSection.append('p').html(_t.html('splash.text', {
86511 version: context.version,
86512 website: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/develop/CHANGELOG.md#whats-new">changelog</a>',
86513 github: '<a target="_blank" href="https://github.com/openstreetmap/iD/issues">github.com</a>'
86515 modalSection.append('p').html(_t.html('splash.privacy', {
86516 updateMessage: updateMessage,
86517 privacyLink: '<a target="_blank" href="https://github.com/openstreetmap/iD/blob/release/PRIVACY.md">' + _t('splash.privacy_policy') + '</a>'
86519 var buttonWrap = introModal.append('div').attr('class', 'modal-actions');
86520 var walkthrough = buttonWrap.append('button').attr('class', 'walkthrough').on('click', function () {
86521 context.container().call(uiIntro(context));
86522 modalSelection.close();
86524 walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
86525 walkthrough.append('div').html(_t.html('splash.walkthrough'));
86526 var startEditing = buttonWrap.append('button').attr('class', 'start-editing').on('click', modalSelection.close);
86527 startEditing.append('svg').attr('class', 'logo logo-features').append('use').attr('xlink:href', '#iD-logo-features');
86528 startEditing.append('div').html(_t.html('splash.start'));
86529 modalSelection.select('button.close').attr('class', 'hide');
86533 function uiStatus(context) {
86534 var osm = context.connection();
86535 return function (selection) {
86538 function update(err, apiStatus) {
86539 selection.html('');
86542 if (apiStatus === 'connectionSwitched') {
86543 // if the connection was just switched, we can't rely on
86544 // the status (we're getting the status of the previous api)
86546 } else if (apiStatus === 'rateLimited') {
86547 selection.html(_t.html('osm_api_status.message.rateLimit')).append('a').attr('href', '#').attr('class', 'api-status-login').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html('login')).on('click.login', function (d3_event) {
86548 d3_event.preventDefault();
86549 osm.authenticate();
86552 // don't allow retrying too rapidly
86553 var throttledRetry = throttle(function () {
86554 // try loading the visible tiles
86555 context.loadTiles(context.projection); // manually reload the status too in case all visible tiles were already loaded
86557 osm.reloadApiStatus();
86558 }, 2000); // eslint-disable-next-line no-warning-comments
86559 // TODO: nice messages for different error types
86562 selection.html(_t.html('osm_api_status.message.error') + ' ').append('a').attr('href', '#') // let the user manually retry their connection directly
86563 .html(_t.html('osm_api_status.retry')).on('click.retry', function (d3_event) {
86564 d3_event.preventDefault();
86568 } else if (apiStatus === 'readonly') {
86569 selection.html(_t.html('osm_api_status.message.readonly'));
86570 } else if (apiStatus === 'offline') {
86571 selection.html(_t.html('osm_api_status.message.offline'));
86574 selection.attr('class', 'api-status ' + (err ? 'error' : apiStatus));
86577 osm.on('apiStatusChange.uiStatus', update);
86578 context.history().on('storage_error', function () {
86579 selection.html(_t.html('osm_api_status.message.local_storage_full'));
86580 selection.attr('class', 'api-status error');
86581 }); // reload the status periodically regardless of other factors
86583 window.setInterval(function () {
86584 osm.reloadApiStatus();
86585 }, 90000); // load the initial status in case no OSM data was loaded yet
86587 osm.reloadApiStatus();
86591 function modeDrawArea(context, wayID, startGraph, button) {
86596 var behavior = behaviorDrawWay(context, wayID, mode, startGraph).on('rejectedSelfIntersection.modeDrawArea', function () {
86597 context.ui().flash.iconName('#iD-icon-no').label(_t('self_intersection.error.areas'))();
86599 mode.wayID = wayID;
86601 mode.enter = function () {
86602 context.install(behavior);
86605 mode.exit = function () {
86606 context.uninstall(behavior);
86609 mode.selectedIDs = function () {
86613 mode.activeID = function () {
86614 return behavior && behavior.activeID() || [];
86620 function modeAddArea(context, mode) {
86621 mode.id = 'add-area';
86622 var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
86623 var defaultTags = {
86626 if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'area');
86628 function actionClose(wayId) {
86629 return function (graph) {
86630 return graph.replace(graph.entity(wayId).close());
86634 function start(loc) {
86635 var startGraph = context.graph();
86636 var node = osmNode({
86642 context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
86643 context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86646 function startFromWay(loc, edge) {
86647 var startGraph = context.graph();
86648 var node = osmNode({
86654 context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id), actionAddMidpoint({
86658 context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86661 function startFromNode(node) {
86662 var startGraph = context.graph();
86666 context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id), actionClose(way.id));
86667 context.enter(modeDrawArea(context, way.id, startGraph, mode.button));
86670 mode.enter = function () {
86671 context.install(behavior);
86674 mode.exit = function () {
86675 context.uninstall(behavior);
86681 function modeAddLine(context, mode) {
86682 mode.id = 'add-line';
86683 var behavior = behaviorAddWay(context).on('start', start).on('startFromWay', startFromWay).on('startFromNode', startFromNode);
86684 var defaultTags = {};
86685 if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'line');
86687 function start(loc) {
86688 var startGraph = context.graph();
86689 var node = osmNode({
86695 context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id));
86696 context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86699 function startFromWay(loc, edge) {
86700 var startGraph = context.graph();
86701 var node = osmNode({
86707 context.perform(actionAddEntity(node), actionAddEntity(way), actionAddVertex(way.id, node.id), actionAddMidpoint({
86711 context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86714 function startFromNode(node) {
86715 var startGraph = context.graph();
86719 context.perform(actionAddEntity(way), actionAddVertex(way.id, node.id));
86720 context.enter(modeDrawLine(context, way.id, startGraph, mode.button));
86723 mode.enter = function () {
86724 context.install(behavior);
86727 mode.exit = function () {
86728 context.uninstall(behavior);
86734 function modeAddPoint(context, mode) {
86735 mode.id = 'add-point';
86736 var behavior = behaviorDraw(context).on('click', add).on('clickWay', addWay).on('clickNode', addNode).on('cancel', cancel).on('finish', cancel);
86737 var defaultTags = {};
86738 if (mode.preset) defaultTags = mode.preset.setTags(defaultTags, 'point');
86740 function add(loc) {
86741 var node = osmNode({
86745 context.perform(actionAddEntity(node), _t('operations.add.annotation.point'));
86746 enterSelectMode(node);
86749 function addWay(loc, edge) {
86750 var node = osmNode({
86753 context.perform(actionAddMidpoint({
86756 }, node), _t('operations.add.annotation.vertex'));
86757 enterSelectMode(node);
86760 function enterSelectMode(node) {
86761 context.enter(modeSelect(context, [node.id]).newFeature(true));
86764 function addNode(node) {
86765 if (Object.keys(defaultTags).length === 0) {
86766 enterSelectMode(node);
86770 var tags = Object.assign({}, node.tags); // shallow copy
86772 for (var key in defaultTags) {
86773 tags[key] = defaultTags[key];
86776 context.perform(actionChangeTags(node.id, tags), _t('operations.add.annotation.point'));
86777 enterSelectMode(node);
86780 function cancel() {
86781 context.enter(modeBrowse(context));
86784 mode.enter = function () {
86785 context.install(behavior);
86788 mode.exit = function () {
86789 context.uninstall(behavior);
86795 function modeSelectNote(context, selectedNoteID) {
86801 var _keybinding = utilKeybinding('select-note');
86803 var _noteEditor = uiNoteEditor(context).on('change', function () {
86804 context.map().pan([0, 0]); // trigger a redraw
86806 var note = checkSelectedID();
86808 context.ui().sidebar.show(_noteEditor.note(note));
86811 var _behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
86812 var _newFeature = false;
86814 function checkSelectedID() {
86815 if (!services.osm) return;
86816 var note = services.osm.getNote(selectedNoteID);
86819 context.enter(modeBrowse(context));
86823 } // class the note as selected, or return to browse mode if the note is gone
86826 function selectNote(d3_event, drawn) {
86827 if (!checkSelectedID()) return;
86828 var selection = context.surface().selectAll('.layer-notes .note-' + selectedNoteID);
86830 if (selection.empty()) {
86831 // Return to browse mode if selected DOM elements have
86832 // disappeared because the user moved them out of view..
86833 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
86835 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
86836 context.enter(modeBrowse(context));
86839 selection.classed('selected', true);
86840 context.selectedNoteID(selectedNoteID);
86845 if (context.container().select('.combobox').size()) return;
86846 context.enter(modeBrowse(context));
86849 mode.zoomToSelected = function () {
86850 if (!services.osm) return;
86851 var note = services.osm.getNote(selectedNoteID);
86854 context.map().centerZoomEase(note.loc, 20);
86858 mode.newFeature = function (val) {
86859 if (!arguments.length) return _newFeature;
86864 mode.enter = function () {
86865 var note = checkSelectedID();
86868 _behaviors.forEach(context.install);
86870 _keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
86872 select(document).call(_keybinding);
86874 var sidebar = context.ui().sidebar;
86875 sidebar.show(_noteEditor.note(note).newNote(_newFeature)); // expand the sidebar, avoid obscuring the note if needed
86877 sidebar.expand(sidebar.intersects(note.extent()));
86878 context.map().on('drawn.select', selectNote);
86881 mode.exit = function () {
86882 _behaviors.forEach(context.uninstall);
86884 select(document).call(_keybinding.unbind);
86885 context.surface().selectAll('.layer-notes .selected').classed('selected hover', false);
86886 context.map().on('drawn.select', null);
86887 context.ui().sidebar.hide();
86888 context.selectedNoteID(null);
86894 function modeAddNote(context) {
86898 description: _t.html('modes.add_note.description'),
86899 key: _t('modes.add_note.key')
86901 var behavior = behaviorDraw(context).on('click', add).on('cancel', cancel).on('finish', cancel);
86903 function add(loc) {
86904 var osm = services.osm;
86906 var note = osmNote({
86911 osm.replaceNote(note); // force a reraw (there is no history change that would otherwise do this)
86913 context.map().pan([0, 0]);
86914 context.selectedNoteID(note.id).enter(modeSelectNote(context, note.id).newFeature(true));
86917 function cancel() {
86918 context.enter(modeBrowse(context));
86921 mode.enter = function () {
86922 context.install(behavior);
86925 mode.exit = function () {
86926 context.uninstall(behavior);
86932 var JXON = new function () {
86933 var sValueProp = 'keyValue',
86934 sAttributesProp = 'keyAttributes',
86937 /* you can customize these values */
86940 rIsBool = /^(?:true|false)$/i;
86942 function parseText(sValue) {
86943 if (rIsNull.test(sValue)) {
86947 if (rIsBool.test(sValue)) {
86948 return sValue.toLowerCase() === 'true';
86951 if (isFinite(sValue)) {
86952 return parseFloat(sValue);
86955 if (isFinite(Date.parse(sValue))) {
86956 return new Date(sValue);
86962 function EmptyTree() {}
86964 EmptyTree.prototype.toString = function () {
86968 EmptyTree.prototype.valueOf = function () {
86972 function objectify(vValue) {
86973 return vValue === null ? new EmptyTree() : vValue instanceof Object ? vValue : new vValue.constructor(vValue);
86976 function createObjTree(oParentNode, nVerb, bFreeze, bNesteAttr) {
86977 var nLevelStart = aCache.length,
86978 bChildren = oParentNode.hasChildNodes(),
86979 bAttributes = oParentNode.hasAttributes(),
86980 bHighVerb = Boolean(nVerb & 2);
86984 sCollectedTxt = '',
86985 vResult = bHighVerb ? {} :
86986 /* put here the default value for empty nodes: */
86990 for (var oNode, nItem = 0; nItem < oParentNode.childNodes.length; nItem++) {
86991 oNode = oParentNode.childNodes.item(nItem);
86993 if (oNode.nodeType === 4) {
86994 /* nodeType is 'CDATASection' (4) */
86995 sCollectedTxt += oNode.nodeValue;
86996 } else if (oNode.nodeType === 3) {
86997 /* nodeType is 'Text' (3) */
86998 sCollectedTxt += oNode.nodeValue.trim();
86999 } else if (oNode.nodeType === 1 && !oNode.prefix) {
87000 /* nodeType is 'Element' (1) */
87001 aCache.push(oNode);
87006 var nLevelEnd = aCache.length,
87007 vBuiltVal = parseText(sCollectedTxt);
87009 if (!bHighVerb && (bChildren || bAttributes)) {
87010 vResult = nVerb === 0 ? objectify(vBuiltVal) : {};
87013 for (var nElId = nLevelStart; nElId < nLevelEnd; nElId++) {
87014 sProp = aCache[nElId].nodeName.toLowerCase();
87015 vContent = createObjTree(aCache[nElId], nVerb, bFreeze, bNesteAttr);
87017 if (vResult.hasOwnProperty(sProp)) {
87018 if (vResult[sProp].constructor !== Array) {
87019 vResult[sProp] = [vResult[sProp]];
87022 vResult[sProp].push(vContent);
87024 vResult[sProp] = vContent;
87030 var nAttrLen = oParentNode.attributes.length,
87031 sAPrefix = bNesteAttr ? '' : sAttrPref,
87032 oAttrParent = bNesteAttr ? {} : vResult;
87034 for (var oAttrib, nAttrib = 0; nAttrib < nAttrLen; nLength++, nAttrib++) {
87035 oAttrib = oParentNode.attributes.item(nAttrib);
87036 oAttrParent[sAPrefix + oAttrib.name.toLowerCase()] = parseText(oAttrib.value.trim());
87041 Object.freeze(oAttrParent);
87044 vResult[sAttributesProp] = oAttrParent;
87045 nLength -= nAttrLen - 1;
87049 if (nVerb === 3 || (nVerb === 2 || nVerb === 1 && nLength > 0) && sCollectedTxt) {
87050 vResult[sValueProp] = vBuiltVal;
87051 } else if (!bHighVerb && nLength === 0 && sCollectedTxt) {
87052 vResult = vBuiltVal;
87055 if (bFreeze && (bHighVerb || nLength > 0)) {
87056 Object.freeze(vResult);
87059 aCache.length = nLevelStart;
87063 function loadObjTree(oXMLDoc, oParentEl, oParentObj) {
87064 var vValue, oChild;
87066 if (oParentObj instanceof String || oParentObj instanceof Number || oParentObj instanceof Boolean) {
87067 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toString()));
87068 /* verbosity level is 0 */
87069 } else if (oParentObj.constructor === Date) {
87070 oParentEl.appendChild(oXMLDoc.createTextNode(oParentObj.toGMTString()));
87073 for (var sName in oParentObj) {
87074 vValue = oParentObj[sName];
87076 if (isFinite(sName) || vValue instanceof Function) {
87079 /* verbosity level is 0 */
87082 if (sName === sValueProp) {
87083 if (vValue !== null && vValue !== true) {
87084 oParentEl.appendChild(oXMLDoc.createTextNode(vValue.constructor === Date ? vValue.toGMTString() : String(vValue)));
87086 } else if (sName === sAttributesProp) {
87087 /* verbosity level is 3 */
87088 for (var sAttrib in vValue) {
87089 oParentEl.setAttribute(sAttrib, vValue[sAttrib]);
87091 } else if (sName.charAt(0) === sAttrPref) {
87092 oParentEl.setAttribute(sName.slice(1), vValue);
87093 } else if (vValue.constructor === Array) {
87094 for (var nItem = 0; nItem < vValue.length; nItem++) {
87095 oChild = oXMLDoc.createElement(sName);
87096 loadObjTree(oXMLDoc, oChild, vValue[nItem]);
87097 oParentEl.appendChild(oChild);
87100 oChild = oXMLDoc.createElement(sName);
87102 if (vValue instanceof Object) {
87103 loadObjTree(oXMLDoc, oChild, vValue);
87104 } else if (vValue !== null && vValue !== true) {
87105 oChild.appendChild(oXMLDoc.createTextNode(vValue.toString()));
87108 oParentEl.appendChild(oChild);
87113 this.build = function (oXMLParent, nVerbosity
87120 var _nVerb = arguments.length > 1 && typeof nVerbosity === 'number' ? nVerbosity & 3 :
87121 /* put here the default verbosity level: */
87124 return createObjTree(oXMLParent, _nVerb, bFreeze || false, arguments.length > 3 ? bNesteAttributes : _nVerb === 3);
87127 this.unbuild = function (oObjTree) {
87128 var oNewDoc = document.implementation.createDocument('', '', null);
87129 loadObjTree(oNewDoc, oNewDoc, oObjTree);
87133 this.stringify = function (oObjTree) {
87134 return new XMLSerializer().serializeToString(JXON.unbuild(oObjTree));
87136 }(); // var myObject = JXON.build(doc);
87137 // we got our javascript object! try: alert(JSON.stringify(myObject));
87138 // var newDoc = JXON.unbuild(myObject);
87139 // we got our Document instance! try: alert((new XMLSerializer()).serializeToString(newDoc));
87141 function uiConflicts(context) {
87142 var dispatch = dispatch$8('cancel', 'save');
87143 var keybinding = utilKeybinding('conflicts');
87149 var _shownConflictIndex;
87151 function keybindingOn() {
87152 select(document).call(keybinding.on('⎋', cancel, true));
87155 function keybindingOff() {
87156 select(document).call(keybinding.unbind);
87159 function tryAgain() {
87161 dispatch.call('save');
87164 function cancel() {
87166 dispatch.call('cancel');
87169 function conflicts(selection) {
87171 var headerEnter = selection.selectAll('.header').data([0]).enter().append('div').attr('class', 'header fillL');
87172 headerEnter.append('button').attr('class', 'fr').on('click', cancel).call(svgIcon('#iD-icon-close'));
87173 headerEnter.append('h3').html(_t.html('save.conflict.header'));
87174 var bodyEnter = selection.selectAll('.body').data([0]).enter().append('div').attr('class', 'body fillL');
87175 var conflictsHelpEnter = bodyEnter.append('div').attr('class', 'conflicts-help').html(_t.html('save.conflict.help')); // Download changes link
87177 var detected = utilDetect();
87178 var changeset = new osmChangeset();
87179 delete changeset.id; // Export without changeset_id
87181 var data = JXON.stringify(changeset.osmChangeJXON(_origChanges));
87182 var blob = new Blob([data], {
87183 type: 'text/xml;charset=utf-8;'
87185 var fileName = 'changes.osc';
87186 var linkEnter = conflictsHelpEnter.selectAll('.download-changes').append('a').attr('class', 'download-changes');
87188 if (detected.download) {
87189 // All except IE11 and Edge
87190 linkEnter // download the data as a file
87191 .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
87194 linkEnter // open data uri in a new tab
87195 .attr('target', '_blank').on('click.download', function () {
87196 navigator.msSaveBlob(blob, fileName);
87200 linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('save.conflict.download_changes'));
87201 bodyEnter.append('div').attr('class', 'conflict-container fillL3').call(showConflict, 0);
87202 bodyEnter.append('div').attr('class', 'conflicts-done').attr('opacity', 0).style('display', 'none').html(_t.html('save.conflict.done'));
87203 var buttonsEnter = bodyEnter.append('div').attr('class', 'buttons col12 joined conflicts-buttons');
87204 buttonsEnter.append('button').attr('disabled', _conflictList.length > 1).attr('class', 'action conflicts-button col6').html(_t.html('save.title')).on('click.try_again', tryAgain);
87205 buttonsEnter.append('button').attr('class', 'secondary-action conflicts-button col6').html(_t.html('confirm.cancel')).on('click.cancel', cancel);
87208 function showConflict(selection, index) {
87209 index = utilWrap(index, _conflictList.length);
87210 _shownConflictIndex = index;
87211 var parent = select(selection.node().parentNode); // enable save button if this is the last conflict being reviewed..
87213 if (index === _conflictList.length - 1) {
87214 window.setTimeout(function () {
87215 parent.select('.conflicts-button').attr('disabled', null);
87216 parent.select('.conflicts-done').transition().attr('opacity', 1).style('display', 'block');
87220 var conflict = selection.selectAll('.conflict').data([_conflictList[index]]);
87221 conflict.exit().remove();
87222 var conflictEnter = conflict.enter().append('div').attr('class', 'conflict');
87223 conflictEnter.append('h4').attr('class', 'conflict-count').html(_t.html('save.conflict.count', {
87225 total: _conflictList.length
87227 conflictEnter.append('a').attr('class', 'conflict-description').attr('href', '#').html(function (d) {
87229 }).on('click', function (d3_event, d) {
87230 d3_event.preventDefault();
87231 zoomToEntity(d.id);
87233 var details = conflictEnter.append('div').attr('class', 'conflict-detail-container');
87234 details.append('ul').attr('class', 'conflict-detail-list').selectAll('li').data(function (d) {
87235 return d.details || [];
87236 }).enter().append('li').attr('class', 'conflict-detail-item').html(function (d) {
87239 details.append('div').attr('class', 'conflict-choices').call(addChoices);
87240 details.append('div').attr('class', 'conflict-nav-buttons joined cf').selectAll('button').data(['previous', 'next']).enter().append('button').html(function (d) {
87241 return _t.html('save.conflict.' + d);
87242 }).attr('class', 'conflict-nav-button action col6').attr('disabled', function (d, i) {
87243 return i === 0 && index === 0 || i === 1 && index === _conflictList.length - 1 || null;
87244 }).on('click', function (d3_event, d) {
87245 d3_event.preventDefault();
87246 var container = parent.selectAll('.conflict-container');
87247 var sign = d === 'previous' ? -1 : 1;
87248 container.selectAll('.conflict').remove();
87249 container.call(showConflict, index + sign);
87253 function addChoices(selection) {
87254 var choices = selection.append('ul').attr('class', 'layer-list').selectAll('li').data(function (d) {
87255 return d.choices || [];
87258 var choicesEnter = choices.enter().append('li').attr('class', 'layer');
87259 var labelEnter = choicesEnter.append('label');
87260 labelEnter.append('input').attr('type', 'radio').attr('name', function (d) {
87262 }).on('change', function (d3_event, d) {
87263 var ul = this.parentNode.parentNode.parentNode;
87264 ul.__data__.chosen = d.id;
87265 choose(d3_event, ul, d);
87267 labelEnter.append('span').html(function (d) {
87271 choicesEnter.merge(choices).each(function (d) {
87272 var ul = this.parentNode;
87274 if (ul.__data__.chosen === d.id) {
87275 choose(null, ul, d);
87280 function choose(d3_event, ul, datum) {
87281 if (d3_event) d3_event.preventDefault();
87282 select(ul).selectAll('li').classed('active', function (d) {
87283 return d === datum;
87284 }).selectAll('input').property('checked', function (d) {
87285 return d === datum;
87287 var extent = geoExtent();
87289 entity = context.graph().hasEntity(datum.id);
87290 if (entity) extent._extend(entity.extent(context.graph()));
87292 entity = context.graph().hasEntity(datum.id);
87293 if (entity) extent._extend(entity.extent(context.graph()));
87294 zoomToEntity(datum.id, extent);
87297 function zoomToEntity(id, extent) {
87298 context.surface().selectAll('.hover').classed('hover', false);
87299 var entity = context.graph().hasEntity(id);
87303 context.map().trimmedExtent(extent);
87305 context.map().zoomToEase(entity);
87308 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
87310 } // The conflict list should be an array of objects like:
87313 // name: entityName(local),
87314 // details: merge.conflicts(),
87317 // choice(id, keepMine, forceLocal),
87318 // choice(id, keepTheirs, forceRemote)
87323 conflicts.conflictList = function (_) {
87324 if (!arguments.length) return _conflictList;
87329 conflicts.origChanges = function (_) {
87330 if (!arguments.length) return _origChanges;
87335 conflicts.shownEntityIds = function () {
87336 if (_conflictList && typeof _shownConflictIndex === 'number') {
87337 return [_conflictList[_shownConflictIndex].id];
87343 return utilRebind(conflicts, dispatch, 'on');
87346 function uiConfirm(selection) {
87347 var modalSelection = uiModal(selection);
87348 modalSelection.select('.modal').classed('modal-alert', true);
87349 var section = modalSelection.select('.content');
87350 section.append('div').attr('class', 'modal-section header');
87351 section.append('div').attr('class', 'modal-section message-text');
87352 var buttons = section.append('div').attr('class', 'modal-section buttons cf');
87354 modalSelection.okButton = function () {
87355 buttons.append('button').attr('class', 'button ok-button action').on('click.confirm', function () {
87356 modalSelection.remove();
87357 }).html(_t.html('confirm.okay')).node().focus();
87358 return modalSelection;
87361 return modalSelection;
87364 function uiChangesetEditor(context) {
87365 var dispatch = dispatch$8('change');
87366 var formFields = uiFormFields(context);
87367 var commentCombo = uiCombobox(context, 'comment').caseSensitive(true);
87375 function changesetEditor(selection) {
87379 function render(selection) {
87380 var initial = false;
87384 var presets = _mainPresetIndex;
87385 _fieldsArr = [uiField(context, presets.field('comment'), null, {
87388 }), uiField(context, presets.field('source'), null, {
87391 }), uiField(context, presets.field('hashtags'), null, {
87396 _fieldsArr.forEach(function (field) {
87397 field.on('change', function (t, onInput) {
87398 dispatch.call('change', field, undefined, t, onInput);
87403 _fieldsArr.forEach(function (field) {
87407 selection.call(formFields.fieldsArr(_fieldsArr));
87410 var commentField = selection.select('.form-field-comment textarea');
87411 var commentNode = commentField.node();
87414 commentNode.focus();
87415 commentNode.select();
87416 } // trigger a 'blur' event so that comment field can be cleaned
87417 // and checked for hashtags, even if retrieved from localstorage
87420 utilTriggerEvent(commentField, 'blur');
87421 var osm = context.connection();
87424 osm.userChangesets(function (err, changesets) {
87426 var comments = changesets.map(function (changeset) {
87427 var comment = changeset.tags.comment;
87432 }).filter(Boolean);
87433 commentField.call(commentCombo.data(utilArrayUniqBy(comments, 'title')));
87436 } // Add warning if comment mentions Google
87439 var hasGoogle = _tags.comment.match(/google/i);
87441 var commentWarning = selection.select('.form-field-comment').selectAll('.comment-warning').data(hasGoogle ? [0] : []);
87442 commentWarning.exit().transition().duration(200).style('opacity', 0).remove();
87443 var commentEnter = commentWarning.enter().insert('div', '.tag-reference-body').attr('class', 'field-warning comment-warning').style('opacity', 0);
87444 commentEnter.append('a').attr('target', '_blank').call(svgIcon('#iD-icon-alert', 'inline')).attr('href', _t('commit.google_warning_link')).append('span').html(_t.html('commit.google_warning'));
87445 commentEnter.transition().duration(200).style('opacity', 1);
87448 changesetEditor.tags = function (_) {
87449 if (!arguments.length) return _tags;
87450 _tags = _; // Don't reset _fieldsArr here.
87452 return changesetEditor;
87455 changesetEditor.changesetID = function (_) {
87456 if (!arguments.length) return _changesetID;
87457 if (_changesetID === _) return changesetEditor;
87460 return changesetEditor;
87463 return utilRebind(changesetEditor, dispatch, 'on');
87466 function uiSectionChanges(context) {
87467 var detected = utilDetect();
87468 var _discardTags = {};
87469 _mainFileFetcher.get('discarded').then(function (d) {
87471 })["catch"](function () {
87474 var section = uiSection('changes-list', context).label(function () {
87475 var history = context.history();
87476 var summary = history.difference().summary();
87477 return _t('inspector.title_count', {
87478 title: _t.html('commit.changes'),
87479 count: summary.length
87481 }).disclosureContent(renderDisclosureContent);
87483 function renderDisclosureContent(selection) {
87484 var history = context.history();
87485 var summary = history.difference().summary();
87486 var container = selection.selectAll('.commit-section').data([0]);
87487 var containerEnter = container.enter().append('div').attr('class', 'commit-section');
87488 containerEnter.append('ul').attr('class', 'changeset-list');
87489 container = containerEnter.merge(container);
87490 var items = container.select('ul').selectAll('li').data(summary);
87491 var itemsEnter = items.enter().append('li').attr('class', 'change-item');
87492 var buttons = itemsEnter.append('button').on('mouseover', mouseover).on('mouseout', mouseout).on('click', click);
87493 buttons.each(function (d) {
87494 select(this).call(svgIcon('#iD-icon-' + d.entity.geometry(d.graph), 'pre-text ' + d.changeType));
87496 buttons.append('span').attr('class', 'change-type').html(function (d) {
87497 return _t.html('commit.' + d.changeType) + ' ';
87499 buttons.append('strong').attr('class', 'entity-type').html(function (d) {
87500 var matched = _mainPresetIndex.match(d.entity, d.graph);
87501 return matched && matched.name() || utilDisplayType(d.entity.id);
87503 buttons.append('span').attr('class', 'entity-name').html(function (d) {
87504 var name = utilDisplayName(d.entity) || '',
87511 return string += ' ' + name;
87513 items = itemsEnter.merge(items); // Download changeset link
87515 var changeset = new osmChangeset().update({
87518 var changes = history.changes(actionDiscardTags(history.difference(), _discardTags));
87519 delete changeset.id; // Export without chnageset_id
87521 var data = JXON.stringify(changeset.osmChangeJXON(changes));
87522 var blob = new Blob([data], {
87523 type: 'text/xml;charset=utf-8;'
87525 var fileName = 'changes.osc';
87526 var linkEnter = container.selectAll('.download-changes').data([0]).enter().append('a').attr('class', 'download-changes');
87528 if (detected.download) {
87529 // All except IE11 and Edge
87530 linkEnter // download the data as a file
87531 .attr('href', window.URL.createObjectURL(blob)).attr('download', fileName);
87534 linkEnter // open data uri in a new tab
87535 .attr('target', '_blank').on('click.download', function () {
87536 navigator.msSaveBlob(blob, fileName);
87540 linkEnter.call(svgIcon('#iD-icon-load', 'inline')).append('span').html(_t.html('commit.download_changes'));
87542 function mouseover(d) {
87544 context.surface().selectAll(utilEntityOrMemberSelector([d.entity.id], context.graph())).classed('hover', true);
87548 function mouseout() {
87549 context.surface().selectAll('.hover').classed('hover', false);
87552 function click(d3_event, change) {
87553 if (change.changeType !== 'deleted') {
87554 var entity = change.entity;
87555 context.map().zoomToEase(entity);
87556 context.surface().selectAll(utilEntityOrMemberSelector([entity.id], context.graph())).classed('hover', true);
87564 function uiCommitWarnings(context) {
87565 function commitWarnings(selection) {
87566 var issuesBySeverity = context.validator().getIssuesBySeverity({
87569 includeDisabledRules: true
87572 for (var severity in issuesBySeverity) {
87573 var issues = issuesBySeverity[severity];
87575 if (severity !== 'error') {
87576 // exclude 'fixme' and similar - #8603
87577 issues = issues.filter(function (issue) {
87578 return issue.type !== 'help_request';
87582 var section = severity + '-section';
87583 var issueItem = severity + '-item';
87584 var container = selection.selectAll('.' + section).data(issues.length ? [0] : []);
87585 container.exit().remove();
87586 var containerEnter = container.enter().append('div').attr('class', 'modal-section ' + section + ' fillL2');
87587 containerEnter.append('h3').html(severity === 'warning' ? _t.html('commit.warnings') : _t.html('commit.errors'));
87588 containerEnter.append('ul').attr('class', 'changeset-list');
87589 container = containerEnter.merge(container);
87590 var items = container.select('ul').selectAll('li').data(issues, function (d) {
87593 items.exit().remove();
87594 var itemsEnter = items.enter().append('li').attr('class', issueItem);
87595 var buttons = itemsEnter.append('button').on('mouseover', function (d3_event, d) {
87597 context.surface().selectAll(utilEntityOrMemberSelector(d.entityIds, context.graph())).classed('hover', true);
87599 }).on('mouseout', function () {
87600 context.surface().selectAll('.hover').classed('hover', false);
87601 }).on('click', function (d3_event, d) {
87602 context.validator().focusIssue(d);
87604 buttons.call(svgIcon('#iD-icon-alert', 'pre-text'));
87605 buttons.append('strong').attr('class', 'issue-message');
87606 buttons.filter(function (d) {
87608 }).call(uiTooltip().title(function (d) {
87610 }).placement('top'));
87611 items = itemsEnter.merge(items);
87612 items.selectAll('.issue-message').html(function (d) {
87613 return d.message(context);
87618 return commitWarnings;
87621 var readOnlyTags = [/^changesets_count$/, /^created_by$/, /^ideditor:/, /^imagery_used$/, /^host$/, /^locale$/, /^warnings:/, /^resolved:/, /^closed:note$/, /^closed:keepright$/, /^closed:improveosm:/, /^closed:osmose:/]; // treat most punctuation (except -, _, +, &) as hashtag delimiters - #4398
87622 // from https://stackoverflow.com/a/25575009
87624 var hashtagRegex = /(#[^\u2000-\u206F\u2E00-\u2E7F\s\\'!"#$%()*,.\/:;<=>?@\[\]^`{|}~]+)/g;
87625 function uiCommit(context) {
87626 var dispatch = dispatch$8('cancel');
87632 var changesetEditor = uiChangesetEditor(context).on('change', changeTags);
87633 var rawTagEditor = uiSectionRawTagEditor('changeset-tag-editor', context).on('change', changeTags).readOnlyTags(readOnlyTags);
87634 var commitChanges = uiSectionChanges(context);
87635 var commitWarnings = uiCommitWarnings(context);
87637 function commit(selection) {
87638 _selection = selection; // Initialize changeset if one does not exist yet.
87640 if (!context.changeset) initChangeset();
87641 loadDerivedChangesetTags();
87642 selection.call(render);
87645 function initChangeset() {
87646 // expire stored comment, hashtags, source after cutoff datetime - #3947 #4899
87647 var commentDate = +corePreferences('commentDate') || 0;
87648 var currDate = Date.now();
87649 var cutoff = 2 * 86400 * 1000; // 2 days
87651 if (commentDate > currDate || currDate - commentDate > cutoff) {
87652 corePreferences('comment', null);
87653 corePreferences('hashtags', null);
87654 corePreferences('source', null);
87655 } // load in explicitly-set values, if any
87658 if (context.defaultChangesetComment()) {
87659 corePreferences('comment', context.defaultChangesetComment());
87660 corePreferences('commentDate', Date.now());
87663 if (context.defaultChangesetSource()) {
87664 corePreferences('source', context.defaultChangesetSource());
87665 corePreferences('commentDate', Date.now());
87668 if (context.defaultChangesetHashtags()) {
87669 corePreferences('hashtags', context.defaultChangesetHashtags());
87670 corePreferences('commentDate', Date.now());
87673 var detected = utilDetect();
87675 comment: corePreferences('comment') || '',
87676 created_by: context.cleanTagValue('iD ' + context.version),
87677 host: context.cleanTagValue(detected.host),
87678 locale: context.cleanTagValue(_mainLocalizer.localeCode())
87679 }; // call findHashtags initially - this will remove stored
87680 // hashtags if any hashtags are found in the comment - #4304
87682 findHashtags(tags, true);
87683 var hashtags = corePreferences('hashtags');
87686 tags.hashtags = hashtags;
87689 var source = corePreferences('source');
87692 tags.source = source;
87695 var photoOverlaysUsed = context.history().photoOverlaysUsed();
87697 if (photoOverlaysUsed.length) {
87698 var sources = (tags.source || '').split(';'); // include this tag for any photo layer
87700 if (sources.indexOf('streetlevel imagery') === -1) {
87701 sources.push('streetlevel imagery');
87702 } // add the photo overlays used during editing as sources
87705 photoOverlaysUsed.forEach(function (photoOverlay) {
87706 if (sources.indexOf(photoOverlay) === -1) {
87707 sources.push(photoOverlay);
87710 tags.source = context.cleanTagValue(sources.join(';'));
87713 context.changeset = new osmChangeset({
87716 } // Calculates read-only metadata tags based on the user's editing session and applies
87717 // them to the changeset.
87720 function loadDerivedChangesetTags() {
87721 var osm = context.connection();
87723 var tags = Object.assign({}, context.changeset.tags); // shallow copy
87724 // assign tags for imagery used
87726 var imageryUsed = context.cleanTagValue(context.history().imageryUsed().join(';'));
87727 tags.imagery_used = imageryUsed || 'None'; // assign tags for closed issues and notes
87729 var osmClosed = osm.getClosedIDs();
87732 if (osmClosed.length) {
87733 tags['closed:note'] = context.cleanTagValue(osmClosed.join(';'));
87736 if (services.keepRight) {
87737 var krClosed = services.keepRight.getClosedIDs();
87739 if (krClosed.length) {
87740 tags['closed:keepright'] = context.cleanTagValue(krClosed.join(';'));
87744 if (services.improveOSM) {
87745 var iOsmClosed = services.improveOSM.getClosedCounts();
87747 for (itemType in iOsmClosed) {
87748 tags['closed:improveosm:' + itemType] = context.cleanTagValue(iOsmClosed[itemType].toString());
87752 if (services.osmose) {
87753 var osmoseClosed = services.osmose.getClosedCounts();
87755 for (itemType in osmoseClosed) {
87756 tags['closed:osmose:' + itemType] = context.cleanTagValue(osmoseClosed[itemType].toString());
87758 } // remove existing issue counts
87761 for (var key in tags) {
87762 if (key.match(/(^warnings:)|(^resolved:)/)) {
87767 function addIssueCounts(issues, prefix) {
87768 var issuesByType = utilArrayGroupBy(issues, 'type');
87770 for (var issueType in issuesByType) {
87771 var issuesOfType = issuesByType[issueType];
87773 if (issuesOfType[0].subtype) {
87774 var issuesBySubtype = utilArrayGroupBy(issuesOfType, 'subtype');
87776 for (var issueSubtype in issuesBySubtype) {
87777 var issuesOfSubtype = issuesBySubtype[issueSubtype];
87778 tags[prefix + ':' + issueType + ':' + issueSubtype] = context.cleanTagValue(issuesOfSubtype.length.toString());
87781 tags[prefix + ':' + issueType] = context.cleanTagValue(issuesOfType.length.toString());
87784 } // add counts of warnings generated by the user's edits
87787 var warnings = context.validator().getIssuesBySeverity({
87790 includeIgnored: true,
87791 includeDisabledRules: true
87792 }).warning.filter(function (issue) {
87793 return issue.type !== 'help_request';
87794 }); // exclude 'fixme' and similar - #8603
87796 addIssueCounts(warnings, 'warnings'); // add counts of issues resolved by the user's edits
87798 var resolvedIssues = context.validator().getResolvedIssues();
87799 addIssueCounts(resolvedIssues, 'resolved');
87800 context.changeset = context.changeset.update({
87805 function render(selection) {
87806 var osm = context.connection();
87808 var header = selection.selectAll('.header').data([0]);
87809 var headerTitle = header.enter().append('div').attr('class', 'header fillL');
87810 headerTitle.append('div').append('h3').html(_t.html('commit.title'));
87811 headerTitle.append('button').attr('class', 'close').on('click', function () {
87812 dispatch.call('cancel', this);
87813 }).call(svgIcon('#iD-icon-close'));
87814 var body = selection.selectAll('.body').data([0]);
87815 body = body.enter().append('div').attr('class', 'body').merge(body); // Changeset Section
87817 var changesetSection = body.selectAll('.changeset-editor').data([0]);
87818 changesetSection = changesetSection.enter().append('div').attr('class', 'modal-section changeset-editor').merge(changesetSection);
87819 changesetSection.call(changesetEditor.changesetID(context.changeset.id).tags(context.changeset.tags)); // Warnings
87821 body.call(commitWarnings); // Upload Explanation
87823 var saveSection = body.selectAll('.save-section').data([0]);
87824 saveSection = saveSection.enter().append('div').attr('class', 'modal-section save-section fillL').merge(saveSection);
87825 var prose = saveSection.selectAll('.commit-info').data([0]);
87827 if (prose.enter().size()) {
87828 // first time, make sure to update user details in prose
87829 _userDetails = null;
87832 prose = prose.enter().append('p').attr('class', 'commit-info').html(_t.html('commit.upload_explanation')).merge(prose); // always check if this has changed, but only update prose.html()
87833 // if needed, because it can trigger a style recalculation
87835 osm.userDetails(function (err, user) {
87837 if (_userDetails === user) return; // no change
87839 _userDetails = user;
87840 var userLink = select(document.createElement('div'));
87842 if (user.image_url) {
87843 userLink.append('img').attr('src', user.image_url).attr('class', 'icon pre-text user-icon');
87846 userLink.append('a').attr('class', 'user-info').html(user.display_name).attr('href', osm.userURL(user.display_name)).attr('target', '_blank');
87847 prose.html(_t.html('commit.upload_explanation_with_user', {
87848 user: userLink.html()
87850 }); // Request Review
87852 var requestReview = saveSection.selectAll('.request-review').data([0]); // Enter
87854 var requestReviewEnter = requestReview.enter().append('div').attr('class', 'request-review');
87855 var requestReviewDomId = utilUniqueDomId('commit-input-request-review');
87856 var labelEnter = requestReviewEnter.append('label').attr('for', requestReviewDomId);
87858 if (!labelEnter.empty()) {
87859 labelEnter.call(uiTooltip().title(_t.html('commit.request_review_info')).placement('top'));
87862 labelEnter.append('input').attr('type', 'checkbox').attr('id', requestReviewDomId);
87863 labelEnter.append('span').html(_t.html('commit.request_review')); // Update
87865 requestReview = requestReview.merge(requestReviewEnter);
87866 var requestReviewInput = requestReview.selectAll('input').property('checked', isReviewRequested(context.changeset.tags)).on('change', toggleRequestReview); // Buttons
87868 var buttonSection = saveSection.selectAll('.buttons').data([0]); // enter
87870 var buttonEnter = buttonSection.enter().append('div').attr('class', 'buttons fillL');
87871 buttonEnter.append('button').attr('class', 'secondary-action button cancel-button').append('span').attr('class', 'label').html(_t.html('commit.cancel'));
87872 var uploadButton = buttonEnter.append('button').attr('class', 'action button save-button');
87873 uploadButton.append('span').attr('class', 'label').html(_t.html('commit.save'));
87874 var uploadBlockerTooltipText = getUploadBlockerMessage(); // update
87876 buttonSection = buttonSection.merge(buttonEnter);
87877 buttonSection.selectAll('.cancel-button').on('click.cancel', function () {
87878 dispatch.call('cancel', this);
87880 buttonSection.selectAll('.save-button').classed('disabled', uploadBlockerTooltipText !== null).on('click.save', function () {
87881 if (!select(this).classed('disabled')) {
87882 this.blur(); // avoid keeping focus on the button - #4641
87884 for (var key in context.changeset.tags) {
87885 // remove any empty keys before upload
87886 if (!key) delete context.changeset.tags[key];
87889 context.uploader().save(context.changeset);
87891 }); // remove any existing tooltip
87893 uiTooltip().destroyAny(buttonSection.selectAll('.save-button'));
87895 if (uploadBlockerTooltipText) {
87896 buttonSection.selectAll('.save-button').call(uiTooltip().title(uploadBlockerTooltipText).placement('top'));
87897 } // Raw Tag Editor
87900 var tagSection = body.selectAll('.tag-section.raw-tag-editor').data([0]);
87901 tagSection = tagSection.enter().append('div').attr('class', 'modal-section tag-section raw-tag-editor').merge(tagSection);
87902 tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
87904 var changesSection = body.selectAll('.commit-changes-section').data([0]);
87905 changesSection = changesSection.enter().append('div').attr('class', 'modal-section commit-changes-section').merge(changesSection); // Change summary
87907 changesSection.call(commitChanges.render);
87909 function toggleRequestReview() {
87910 var rr = requestReviewInput.property('checked');
87912 review_requested: rr ? 'yes' : undefined
87914 tagSection.call(rawTagEditor.tags(Object.assign({}, context.changeset.tags)) // shallow copy
87919 function getUploadBlockerMessage() {
87920 var errors = context.validator().getIssuesBySeverity({
87925 if (errors.length) {
87926 return _t('commit.outstanding_errors_message', {
87927 count: errors.length
87930 var hasChangesetComment = context.changeset && context.changeset.tags.comment && context.changeset.tags.comment.trim().length;
87932 if (!hasChangesetComment) {
87933 return _t('commit.comment_needed_message');
87940 function changeTags(_, changed, onInput) {
87941 if (changed.hasOwnProperty('comment')) {
87942 if (changed.comment === undefined) {
87943 changed.comment = '';
87947 corePreferences('comment', changed.comment);
87948 corePreferences('commentDate', Date.now());
87952 if (changed.hasOwnProperty('source')) {
87953 if (changed.source === undefined) {
87954 corePreferences('source', null);
87955 } else if (!onInput) {
87956 corePreferences('source', changed.source);
87957 corePreferences('commentDate', Date.now());
87959 } // no need to update `prefs` for `hashtags` here since it's done in `updateChangeset`
87962 updateChangeset(changed, onInput);
87965 _selection.call(render);
87969 function findHashtags(tags, commentOnly) {
87970 var detectedHashtags = commentHashtags();
87972 if (detectedHashtags.length) {
87973 // always remove stored hashtags if there are hashtags in the comment - #4304
87974 corePreferences('hashtags', null);
87977 if (!detectedHashtags.length || !commentOnly) {
87978 detectedHashtags = detectedHashtags.concat(hashtagHashtags());
87981 var allLowerCase = new Set();
87982 return detectedHashtags.filter(function (hashtag) {
87983 // Compare tags as lowercase strings, but keep original case tags
87984 var lowerCase = hashtag.toLowerCase();
87986 if (!allLowerCase.has(lowerCase)) {
87987 allLowerCase.add(lowerCase);
87992 }); // Extract hashtags from `comment`
87994 function commentHashtags() {
87995 var matches = (tags.comment || '').replace(/http\S*/g, '') // drop anything that looks like a URL - #4289
87996 .match(hashtagRegex);
87997 return matches || [];
87998 } // Extract and clean hashtags from `hashtags`
88001 function hashtagHashtags() {
88002 var matches = (tags.hashtags || '').split(/[,;\s]+/).map(function (s) {
88003 if (s[0] !== '#') {
88008 var matched = s.match(hashtagRegex);
88009 return matched && matched[0];
88010 }).filter(Boolean); // exclude falsy
88012 return matches || [];
88016 function isReviewRequested(tags) {
88017 var rr = tags.review_requested;
88018 if (rr === undefined) return false;
88019 rr = rr.trim().toLowerCase();
88020 return !(rr === '' || rr === 'no');
88023 function updateChangeset(changed, onInput) {
88024 var tags = Object.assign({}, context.changeset.tags); // shallow copy
88026 Object.keys(changed).forEach(function (k) {
88027 var v = changed[k];
88028 k = context.cleanTagKey(k);
88029 if (readOnlyTags.indexOf(k) !== -1) return;
88031 if (v === undefined) {
88033 } else if (onInput) {
88036 tags[k] = context.cleanTagValue(v);
88041 // when changing the comment, override hashtags with any found in comment.
88042 var commentOnly = changed.hasOwnProperty('comment') && changed.comment !== '';
88043 var arr = findHashtags(tags, commentOnly);
88046 tags.hashtags = context.cleanTagValue(arr.join(';'));
88047 corePreferences('hashtags', tags.hashtags);
88049 delete tags.hashtags;
88050 corePreferences('hashtags', null);
88052 } // always update userdetails, just in case user reauthenticates as someone else
88055 if (_userDetails && _userDetails.changesets_count !== undefined) {
88056 var changesetsCount = parseInt(_userDetails.changesets_count, 10) + 1; // #4283
88058 tags.changesets_count = String(changesetsCount); // first 100 edits - new user
88060 if (changesetsCount <= 100) {
88062 s = corePreferences('walkthrough_completed');
88065 tags['ideditor:walkthrough_completed'] = s;
88068 s = corePreferences('walkthrough_progress');
88071 tags['ideditor:walkthrough_progress'] = s;
88074 s = corePreferences('walkthrough_started');
88077 tags['ideditor:walkthrough_started'] = s;
88081 delete tags.changesets_count;
88084 if (!fastDeepEqual(context.changeset.tags, tags)) {
88085 context.changeset = context.changeset.update({
88091 commit.reset = function () {
88092 context.changeset = null;
88095 return utilRebind(commit, dispatch, 'on');
88098 // for punction see https://stackoverflow.com/a/21224179
88100 function simplify(str) {
88101 if (typeof str !== 'string') return '';
88102 return diacritics.remove(str.replace(/&/g, 'and').replace(/İ/ig, 'i').replace(/[\s\-=_!"#%'*{},.\/:;?\(\)\[\]@\\$\^*+<>«»~`’\u00a1\u00a7\u00b6\u00b7\u00bf\u037e\u0387\u055a-\u055f\u0589\u05c0\u05c3\u05c6\u05f3\u05f4\u0609\u060a\u060c\u060d\u061b\u061e\u061f\u066a-\u066d\u06d4\u0700-\u070d\u07f7-\u07f9\u0830-\u083e\u085e\u0964\u0965\u0970\u0af0\u0df4\u0e4f\u0e5a\u0e5b\u0f04-\u0f12\u0f14\u0f85\u0fd0-\u0fd4\u0fd9\u0fda\u104a-\u104f\u10fb\u1360-\u1368\u166d\u166e\u16eb-\u16ed\u1735\u1736\u17d4-\u17d6\u17d8-\u17da\u1800-\u1805\u1807-\u180a\u1944\u1945\u1a1e\u1a1f\u1aa0-\u1aa6\u1aa8-\u1aad\u1b5a-\u1b60\u1bfc-\u1bff\u1c3b-\u1c3f\u1c7e\u1c7f\u1cc0-\u1cc7\u1cd3\u200b-\u200f\u2016\u2017\u2020-\u2027\u2030-\u2038\u203b-\u203e\u2041-\u2043\u2047-\u2051\u2053\u2055-\u205e\u2cf9-\u2cfc\u2cfe\u2cff\u2d70\u2e00\u2e01\u2e06-\u2e08\u2e0b\u2e0e-\u2e16\u2e18\u2e19\u2e1b\u2e1e\u2e1f\u2e2a-\u2e2e\u2e30-\u2e39\u3001-\u3003\u303d\u30fb\ua4fe\ua4ff\ua60d-\ua60f\ua673\ua67e\ua6f2-\ua6f7\ua874-\ua877\ua8ce\ua8cf\ua8f8-\ua8fa\ua92e\ua92f\ua95f\ua9c1-\ua9cd\ua9de\ua9df\uaa5c-\uaa5f\uaade\uaadf\uaaf0\uaaf1\uabeb\ufe10-\ufe16\ufe19\ufe30\ufe45\ufe46\ufe49-\ufe4c\ufe50-\ufe52\ufe54-\ufe57\ufe5f-\ufe61\ufe68\ufe6a\ufe6b\ufeff\uff01-\uff03\uff05-\uff07\uff0a\uff0c\uff0e\uff0f\uff1a\uff1b\uff1f\uff20\uff3c\uff61\uff64\uff65]+/g, '').toLowerCase());
88105 // `resolveStrings`
88106 // Resolves the text strings for a given community index item
88109 // `item`: Object containing the community index item
88110 // `defaults`: Object containing the community index default strings
88111 // `localizerFn?`: optional function we will call to do the localization.
88112 // This function should be like the iD `t()` function that
88113 // accepts a `stringID` and returns a localized string
88116 // An Object containing all the resolved strings:
88118 // name: 'talk-ru Mailing List',
88119 // url: 'https://lists.openstreetmap.org/listinfo/talk-ru',
88120 // signupUrl: 'https://example.url/signup',
88121 // description: 'A one line description',
88122 // extendedDescription: 'Extended description',
88123 // nameHTML: '<a href="the url">the name</a>',
88124 // urlHTML: '<a href="the url">the url</a>',
88125 // signupUrlHTML: '<a href="the signupUrl">the signupUrl</a>',
88126 // descriptionHTML: the description, with urls and signupUrls linkified,
88127 // extendedDescriptionHTML: the extendedDescription with urls and signupUrls linkified
88131 function resolveStrings(item, defaults, localizerFn) {
88132 var itemStrings = Object.assign({}, item.strings); // shallow clone
88134 var defaultStrings = Object.assign({}, defaults[item.type]); // shallow clone
88136 var anyToken = new RegExp(/(\{\w+\})/, 'gi'); // Pre-localize the item and default strings
88139 if (itemStrings.community) {
88140 var communityID = simplify(itemStrings.community);
88141 itemStrings.community = localizerFn("_communities.".concat(communityID));
88144 ['name', 'description', 'extendedDescription'].forEach(function (prop) {
88145 if (defaultStrings[prop]) defaultStrings[prop] = localizerFn("_defaults.".concat(item.type, ".").concat(prop));
88146 if (itemStrings[prop]) itemStrings[prop] = localizerFn("".concat(item.id, ".").concat(prop));
88150 var replacements = {
88151 account: item.account,
88152 community: itemStrings.community,
88153 signupUrl: itemStrings.signupUrl,
88154 url: itemStrings.url
88155 }; // Resolve URLs first (which may refer to {account})
88157 if (!replacements.signupUrl) {
88158 replacements.signupUrl = resolve(itemStrings.signupUrl || defaultStrings.signupUrl);
88161 if (!replacements.url) {
88162 replacements.url = resolve(itemStrings.url || defaultStrings.url);
88166 name: resolve(itemStrings.name || defaultStrings.name),
88167 url: resolve(itemStrings.url || defaultStrings.url),
88168 signupUrl: resolve(itemStrings.signupUrl || defaultStrings.signupUrl),
88169 description: resolve(itemStrings.description || defaultStrings.description),
88170 extendedDescription: resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription)
88171 }; // Generate linkified strings
88173 resolved.nameHTML = linkify(resolved.url, resolved.name);
88174 resolved.urlHTML = linkify(resolved.url);
88175 resolved.signupUrlHTML = linkify(resolved.signupUrl);
88176 resolved.descriptionHTML = resolve(itemStrings.description || defaultStrings.description, true);
88177 resolved.extendedDescriptionHTML = resolve(itemStrings.extendedDescription || defaultStrings.extendedDescription, true);
88180 function resolve(s, addLinks) {
88181 if (!s) return undefined;
88184 for (var key in replacements) {
88185 var token = "{".concat(key, "}");
88186 var regex = new RegExp(token, 'g');
88188 if (regex.test(result)) {
88189 var replacement = replacements[key];
88191 if (!replacement) {
88192 throw new Error("Cannot resolve token: ".concat(token));
88194 if (addLinks && (key === 'signupUrl' || key === 'url')) {
88195 replacement = linkify(replacement);
88198 result = result.replace(regex, replacement);
88201 } // There shouldn't be any leftover tokens in a resolved string
88204 var leftovers = result.match(anyToken);
88207 throw new Error("Cannot resolve tokens: ".concat(leftovers));
88208 } // Linkify subreddits like `/r/openstreetmap`
88209 // https://github.com/osmlab/osm-community-index/issues/82
88210 // https://github.com/openstreetmap/iD/issues/4997
88213 if (addLinks && item.type === 'reddit') {
88214 result = result.replace(/(\/r\/\w+\/*)/i, function (match) {
88215 return linkify(resolved.url, match);
88222 function linkify(url, text) {
88223 if (!url) return undefined;
88224 text = text || url;
88225 return "<a target=\"_blank\" href=\"".concat(url, "\">").concat(text, "</a>");
88230 function uiSuccess(context) {
88232 var dispatch = dispatch$8('cancel');
88238 ensureOSMCommunityIndex(); // start fetching the data
88240 function ensureOSMCommunityIndex() {
88241 var data = _mainFileFetcher;
88242 return Promise.all([data.get('oci_features'), data.get('oci_resources'), data.get('oci_defaults')]).then(function (vals) {
88243 if (_oci) return _oci; // Merge Custom Features
88245 if (vals[0] && Array.isArray(vals[0].features)) {
88246 _mainLocations.mergeCustomGeoJSON(vals[0]);
88249 var ociResources = Object.values(vals[1].resources);
88251 if (ociResources.length) {
88252 // Resolve all locationSet features.
88253 return _mainLocations.mergeLocationSets(ociResources).then(function () {
88255 resources: ociResources,
88256 defaults: vals[2].defaults
88264 defaults: vals[2].defaults
88269 } // string-to-date parsing in JavaScript is weird
88272 function parseEventDate(when) {
88274 var raw = when.trim();
88277 if (!/Z$/.test(raw)) {
88278 // if no trailing 'Z', add one
88279 raw += 'Z'; // this forces date to be parsed as a UTC date
88282 var parsed = new Date(raw);
88283 return new Date(parsed.toUTCString().substr(0, 25)); // convert to local timezone
88286 function success(selection) {
88287 var header = selection.append('div').attr('class', 'header fillL');
88288 header.append('h3').html(_t.html('success.just_edited'));
88289 header.append('button').attr('class', 'close').on('click', function () {
88290 return dispatch.call('cancel');
88291 }).call(svgIcon('#iD-icon-close'));
88292 var body = selection.append('div').attr('class', 'body save-success fillL');
88293 var summary = body.append('div').attr('class', 'save-summary');
88294 summary.append('h3').html(_t.html('success.thank_you' + (_location ? '_location' : ''), {
88297 summary.append('p').html(_t.html('success.help_html')).append('a').attr('class', 'link-out').attr('target', '_blank').attr('href', _t('success.help_link_url')).call(svgIcon('#iD-icon-out-link', 'inline')).append('span').html(_t.html('success.help_link_text'));
88298 var osm = context.connection();
88300 var changesetURL = osm.changesetURL(_changeset.id);
88301 var table = summary.append('table').attr('class', 'summary-table');
88302 var row = table.append('tr').attr('class', 'summary-row');
88303 row.append('td').attr('class', 'cell-icon summary-icon').append('a').attr('target', '_blank').attr('href', changesetURL).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', '#iD-logo-osm');
88304 var summaryDetail = row.append('td').attr('class', 'cell-detail summary-detail');
88305 summaryDetail.append('a').attr('class', 'cell-detail summary-view-on-osm').attr('target', '_blank').attr('href', changesetURL).html(_t.html('success.view_on_osm'));
88306 summaryDetail.append('div').html(_t.html('success.changeset_id', {
88307 changeset_id: "<a href=\"".concat(changesetURL, "\" target=\"_blank\">").concat(_changeset.id, "</a>")
88308 })); // Get OSM community index features intersecting the map..
88310 ensureOSMCommunityIndex().then(function (oci) {
88311 var loc = context.map().center();
88312 var validLocations = _mainLocations.locationsAt(loc); // Gather the communities
88314 var communities = [];
88315 oci.resources.forEach(function (resource) {
88316 var area = validLocations[resource.locationSetID];
88317 if (!area) return; // Resolve strings
88319 var localizer = function localizer(stringID) {
88320 return _t.html("community.".concat(stringID));
88323 resource.resolved = resolveStrings(resource, oci.defaults, localizer);
88326 order: resource.order || 0,
88329 }); // sort communities by feature area ascending, community order descending
88331 communities.sort(function (a, b) {
88332 return a.area - b.area || b.order - a.order;
88334 body.call(showCommunityLinks, communities.map(function (c) {
88340 function showCommunityLinks(selection, resources) {
88341 var communityLinks = selection.append('div').attr('class', 'save-communityLinks');
88342 communityLinks.append('h3').html(_t.html('success.like_osm'));
88343 var table = communityLinks.append('table').attr('class', 'community-table');
88344 var row = table.selectAll('.community-row').data(resources);
88345 var rowEnter = row.enter().append('tr').attr('class', 'community-row');
88346 rowEnter.append('td').attr('class', 'cell-icon community-icon').append('a').attr('target', '_blank').attr('href', function (d) {
88347 return d.resolved.url;
88348 }).append('svg').attr('class', 'logo-small').append('use').attr('xlink:href', function (d) {
88349 return "#community-".concat(d.type);
88351 var communityDetail = rowEnter.append('td').attr('class', 'cell-detail community-detail');
88352 communityDetail.each(showCommunityDetails);
88353 communityLinks.append('div').attr('class', 'community-missing').html(_t.html('success.missing')).append('a').attr('class', 'link-out').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).attr('href', 'https://github.com/osmlab/osm-community-index/issues').append('span').html(_t.html('success.tell_us'));
88356 function showCommunityDetails(d) {
88357 var selection = select(this);
88358 var communityID = d.id;
88359 selection.append('div').attr('class', 'community-name').html(d.resolved.nameHTML);
88360 selection.append('div').attr('class', 'community-description').html(d.resolved.descriptionHTML); // Create an expanding section if any of these are present..
88362 if (d.resolved.extendedDescriptionHTML || d.languageCodes && d.languageCodes.length) {
88363 selection.append('div').call(uiDisclosure(context, "community-more-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.more')).content(showMore));
88366 var nextEvents = (d.events || []).map(function (event) {
88367 event.date = parseEventDate(event.when);
88369 }).filter(function (event) {
88370 // date is valid and future (or today)
88371 var t = event.date.getTime();
88372 var now = new Date().setHours(0, 0, 0, 0);
88373 return !isNaN(t) && t >= now;
88374 }).sort(function (a, b) {
88375 // sort by date ascending
88376 return a.date < b.date ? -1 : a.date > b.date ? 1 : 0;
88377 }).slice(0, MAXEVENTS); // limit number of events shown
88379 if (nextEvents.length) {
88380 selection.append('div').call(uiDisclosure(context, "community-events-".concat(d.id), false).expanded(false).updatePreference(false).label(_t.html('success.events')).content(showNextEvents)).select('.hide-toggle').append('span').attr('class', 'badge-text').html(nextEvents.length);
88383 function showMore(selection) {
88384 var more = selection.selectAll('.community-more').data([0]);
88385 var moreEnter = more.enter().append('div').attr('class', 'community-more');
88387 if (d.resolved.extendedDescriptionHTML) {
88388 moreEnter.append('div').attr('class', 'community-extended-description').html(d.resolved.extendedDescriptionHTML);
88391 if (d.languageCodes && d.languageCodes.length) {
88392 var languageList = d.languageCodes.map(function (code) {
88393 return _mainLocalizer.languageName(code);
88395 moreEnter.append('div').attr('class', 'community-languages').html(_t.html('success.languages', {
88396 languages: languageList
88401 function showNextEvents(selection) {
88402 var events = selection.append('div').attr('class', 'community-events');
88403 var item = events.selectAll('.community-event').data(nextEvents);
88404 var itemEnter = item.enter().append('div').attr('class', 'community-event');
88405 itemEnter.append('div').attr('class', 'community-event-name').append('a').attr('target', '_blank').attr('href', function (d) {
88407 }).html(function (d) {
88410 if (d.i18n && d.id) {
88411 name = _t("community.".concat(communityID, ".events.").concat(d.id, ".name"), {
88418 itemEnter.append('div').attr('class', 'community-event-when').html(function (d) {
88426 if (d.date.getHours() || d.date.getMinutes()) {
88427 // include time if it has one
88428 options.hour = 'numeric';
88429 options.minute = 'numeric';
88432 return d.date.toLocaleString(_mainLocalizer.localeCode(), options);
88434 itemEnter.append('div').attr('class', 'community-event-where').html(function (d) {
88435 var where = d.where;
88437 if (d.i18n && d.id) {
88438 where = _t("community.".concat(communityID, ".events.").concat(d.id, ".where"), {
88445 itemEnter.append('div').attr('class', 'community-event-description').html(function (d) {
88446 var description = d.description;
88448 if (d.i18n && d.id) {
88449 description = _t("community.".concat(communityID, ".events.").concat(d.id, ".description"), {
88450 "default": description
88454 return description;
88459 success.changeset = function (val) {
88460 if (!arguments.length) return _changeset;
88465 success.location = function (val) {
88466 if (!arguments.length) return _location;
88471 return utilRebind(success, dispatch, 'on');
88474 function modeSave(context) {
88478 var keybinding = utilKeybinding('modeSave');
88479 var commit = uiCommit(context).on('cancel', cancel);
88481 var _conflictsUi; // uiConflicts
88488 var uploader = context.uploader().on('saveStarted.modeSave', function () {
88490 }) // fire off some async work that we want to be ready later
88491 .on('willAttemptUpload.modeSave', prepareForSuccess).on('progressChanged.modeSave', showProgress).on('resultNoChanges.modeSave', function () {
88493 }).on('resultErrors.modeSave', showErrors).on('resultConflicts.modeSave', showConflicts).on('resultSuccess.modeSave', showSuccess);
88495 function cancel() {
88496 context.enter(modeBrowse(context));
88499 function showProgress(num, total) {
88500 var modal = context.container().select('.loading-modal .modal-section');
88501 var progress = modal.selectAll('.progress').data([0]); // enter/update
88503 progress.enter().append('div').attr('class', 'progress').merge(progress).text(_t('save.conflict_progress', {
88509 function showConflicts(changeset, conflicts, origChanges) {
88510 var selection = context.container().select('.sidebar').append('div').attr('class', 'sidebar-component');
88511 context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
88512 _conflictsUi = uiConflicts(context).conflictList(conflicts).origChanges(origChanges).on('cancel', function () {
88513 context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88514 selection.remove();
88516 uploader.cancelConflictResolution();
88517 }).on('save', function () {
88518 context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88519 selection.remove();
88520 uploader.processResolvedConflicts(changeset);
88522 selection.call(_conflictsUi);
88525 function showErrors(errors) {
88527 var selection = uiConfirm(context.container());
88528 selection.select('.modal-section.header').append('h3').text(_t('save.error'));
88529 addErrors(selection, errors);
88530 selection.okButton();
88533 function addErrors(selection, data) {
88534 var message = selection.select('.modal-section.message-text');
88535 var items = message.selectAll('.error-container').data(data);
88536 var enter = items.enter().append('div').attr('class', 'error-container');
88537 enter.append('a').attr('class', 'error-description').attr('href', '#').classed('hide-toggle', true).text(function (d) {
88538 return d.msg || _t('save.unknown_error_details');
88539 }).on('click', function (d3_event) {
88540 d3_event.preventDefault();
88541 var error = select(this);
88542 var detail = select(this.nextElementSibling);
88543 var exp = error.classed('expanded');
88544 detail.style('display', exp ? 'none' : 'block');
88545 error.classed('expanded', !exp);
88547 var details = enter.append('div').attr('class', 'error-detail-container').style('display', 'none');
88548 details.append('ul').attr('class', 'error-detail-list').selectAll('li').data(function (d) {
88549 return d.details || [];
88550 }).enter().append('li').attr('class', 'error-detail-item').text(function (d) {
88553 items.exit().remove();
88556 function showSuccess(changeset) {
88559 var ui = _success.changeset(changeset).location(_location).on('cancel', function () {
88560 context.ui().sidebar.hide();
88563 context.enter(modeBrowse(context).sidebar(ui));
88566 function keybindingOn() {
88567 select(document).call(keybinding.on('⎋', cancel, true));
88570 function keybindingOff() {
88571 select(document).call(keybinding.unbind);
88572 } // Reverse geocode current map location so we can display a message on
88573 // the success screen like "Thank you for editing around place, region."
88576 function prepareForSuccess() {
88577 _success = uiSuccess(context);
88579 if (!services.geocoder) return;
88580 services.geocoder.reverse(context.map().center(), function (err, result) {
88581 if (err || !result || !result.address) return;
88582 var addr = result.address;
88583 var place = addr && (addr.town || addr.city || addr.county) || '';
88584 var region = addr && (addr.state || addr.country) || '';
88585 var separator = place && region ? _t('success.thank_you_where.separator') : '';
88586 _location = _t('success.thank_you_where.format', {
88588 separator: separator,
88594 mode.selectedIDs = function () {
88595 return _conflictsUi ? _conflictsUi.shownEntityIds() : [];
88598 mode.enter = function () {
88600 context.ui().sidebar.expand();
88603 context.ui().sidebar.show(commit);
88607 context.container().selectAll('.main-content').classed('active', false).classed('inactive', true);
88608 var osm = context.connection();
88615 if (osm.authenticated()) {
88618 osm.authenticate(function (err) {
88628 mode.exit = function () {
88630 context.container().selectAll('.main-content').classed('active', true).classed('inactive', false);
88631 context.ui().sidebar.hide();
88637 function modeSelectError(context, selectedErrorID, selectedErrorService) {
88639 id: 'select-error',
88642 var keybinding = utilKeybinding('select-error');
88643 var errorService = services[selectedErrorService];
88646 switch (selectedErrorService) {
88648 errorEditor = uiImproveOsmEditor(context).on('change', function () {
88649 context.map().pan([0, 0]); // trigger a redraw
88651 var error = checkSelectedID();
88652 if (!error) return;
88653 context.ui().sidebar.show(errorEditor.error(error));
88658 errorEditor = uiKeepRightEditor(context).on('change', function () {
88659 context.map().pan([0, 0]); // trigger a redraw
88661 var error = checkSelectedID();
88662 if (!error) return;
88663 context.ui().sidebar.show(errorEditor.error(error));
88668 errorEditor = uiOsmoseEditor(context).on('change', function () {
88669 context.map().pan([0, 0]); // trigger a redraw
88671 var error = checkSelectedID();
88672 if (!error) return;
88673 context.ui().sidebar.show(errorEditor.error(error));
88678 var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
88680 function checkSelectedID() {
88681 if (!errorService) return;
88682 var error = errorService.getError(selectedErrorID);
88685 context.enter(modeBrowse(context));
88691 mode.zoomToSelected = function () {
88692 if (!errorService) return;
88693 var error = errorService.getError(selectedErrorID);
88696 context.map().centerZoomEase(error.loc, 20);
88700 mode.enter = function () {
88701 var error = checkSelectedID();
88702 if (!error) return;
88703 behaviors.forEach(context.install);
88704 keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
88705 select(document).call(keybinding);
88707 var sidebar = context.ui().sidebar;
88708 sidebar.show(errorEditor.error(error));
88709 context.map().on('drawn.select-error', selectError); // class the error as selected, or return to browse mode if the error is gone
88711 function selectError(d3_event, drawn) {
88712 if (!checkSelectedID()) return;
88713 var selection = context.surface().selectAll('.itemId-' + selectedErrorID + '.' + selectedErrorService);
88715 if (selection.empty()) {
88716 // Return to browse mode if selected DOM elements have
88717 // disappeared because the user moved them out of view..
88718 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
88720 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
88721 context.enter(modeBrowse(context));
88724 selection.classed('selected', true);
88725 context.selectedErrorID(selectedErrorID);
88730 if (context.container().select('.combobox').size()) return;
88731 context.enter(modeBrowse(context));
88735 mode.exit = function () {
88736 behaviors.forEach(context.uninstall);
88737 select(document).call(keybinding.unbind);
88738 context.surface().selectAll('.qaItem.selected').classed('selected hover', false);
88739 context.map().on('drawn.select-error', null);
88740 context.ui().sidebar.hide();
88741 context.selectedErrorID(null);
88742 context.features().forceVisible([]);
88748 function uiToolOldDrawModes(context) {
88751 label: _t.html('toolbar.add_feature')
88753 var modes = [modeAddPoint(context, {
88754 title: _t.html('modes.add_point.title'),
88756 description: _t.html('modes.add_point.description'),
88757 preset: _mainPresetIndex.item('point'),
88759 }), modeAddLine(context, {
88760 title: _t.html('modes.add_line.title'),
88762 description: _t.html('modes.add_line.description'),
88763 preset: _mainPresetIndex.item('line'),
88765 }), modeAddArea(context, {
88766 title: _t.html('modes.add_area.title'),
88768 description: _t.html('modes.add_area.description'),
88769 preset: _mainPresetIndex.item('area'),
88773 function enabled() {
88774 return osmEditable();
88777 function osmEditable() {
88778 return context.editable();
88781 modes.forEach(function (mode) {
88782 context.keybinding().on(mode.key, function () {
88783 if (!enabled()) return;
88785 if (mode.id === context.mode().id) {
88786 context.enter(modeBrowse(context));
88788 context.enter(mode);
88793 tool.render = function (selection) {
88794 var wrap = selection.append('div').attr('class', 'joined').style('display', 'flex');
88796 var debouncedUpdate = debounce(update, 500, {
88801 context.map().on('move.modes', debouncedUpdate).on('drawn.modes', debouncedUpdate);
88802 context.on('enter.modes', update);
88805 function update() {
88806 var buttons = wrap.selectAll('button.add-button').data(modes, function (d) {
88810 buttons.exit().remove(); // enter
88812 var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
88813 return d.id + ' add-button bar-button';
88814 }).on('click.mode-buttons', function (d3_event, d) {
88815 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
88817 var currMode = context.mode().id;
88818 if (/^draw/.test(currMode)) return;
88820 if (d.id === currMode) {
88821 context.enter(modeBrowse(context));
88825 }).call(uiTooltip().placement('bottom').title(function (d) {
88826 return d.description;
88827 }).keys(function (d) {
88829 }).scrollContainer(context.container().select('.top-toolbar')));
88830 buttonsEnter.each(function (d) {
88831 select(this).call(svgIcon('#iD-icon-' + d.button));
88833 buttonsEnter.append('span').attr('class', 'label').html(function (mode) {
88835 }); // if we are adding/removing the buttons, check if toolbar has overflowed
88837 if (buttons.enter().size() || buttons.exit().size()) {
88838 context.ui().checkOverflow('.top-toolbar', true);
88842 buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
88844 }).classed('active', function (d) {
88845 return context.mode() && context.mode().button === d.button;
88853 function uiToolNotes(context) {
88856 label: _t.html('modes.add_note.label')
88858 var mode = modeAddNote(context);
88860 function enabled() {
88861 return notesEnabled() && notesEditable();
88864 function notesEnabled() {
88865 var noteLayer = context.layers().layer('notes');
88866 return noteLayer && noteLayer.enabled();
88869 function notesEditable() {
88870 var mode = context.mode();
88871 return context.map().notesEditable() && mode && mode.id !== 'save';
88874 context.keybinding().on(mode.key, function () {
88875 if (!enabled()) return;
88877 if (mode.id === context.mode().id) {
88878 context.enter(modeBrowse(context));
88880 context.enter(mode);
88884 tool.render = function (selection) {
88885 var debouncedUpdate = debounce(update, 500, {
88890 context.map().on('move.notes', debouncedUpdate).on('drawn.notes', debouncedUpdate);
88891 context.on('enter.notes', update);
88894 function update() {
88895 var showNotes = notesEnabled();
88896 var data = showNotes ? [mode] : [];
88897 var buttons = selection.selectAll('button.add-button').data(data, function (d) {
88901 buttons.exit().remove(); // enter
88903 var buttonsEnter = buttons.enter().append('button').attr('class', function (d) {
88904 return d.id + ' add-button bar-button';
88905 }).on('click.notes', function (d3_event, d) {
88906 if (!enabled()) return; // When drawing, ignore accidental clicks on mode buttons - #4042
88908 var currMode = context.mode().id;
88909 if (/^draw/.test(currMode)) return;
88911 if (d.id === currMode) {
88912 context.enter(modeBrowse(context));
88916 }).call(uiTooltip().placement('bottom').title(function (d) {
88917 return d.description;
88918 }).keys(function (d) {
88920 }).scrollContainer(context.container().select('.top-toolbar')));
88921 buttonsEnter.each(function (d) {
88922 select(this).call(svgIcon(d.icon || '#iD-icon-' + d.button));
88923 }); // if we are adding/removing the buttons, check if toolbar has overflowed
88925 if (buttons.enter().size() || buttons.exit().size()) {
88926 context.ui().checkOverflow('.top-toolbar', true);
88930 buttons = buttons.merge(buttonsEnter).classed('disabled', function (d) {
88932 }).classed('active', function (d) {
88933 return context.mode() && context.mode().button === d.button;
88938 tool.uninstall = function () {
88939 context.on('enter.editor.notes', null).on('exit.editor.notes', null).on('enter.notes', null);
88940 context.map().on('move.notes', null).on('drawn.notes', null);
88946 function uiToolSave(context) {
88949 label: _t.html('save.title')
88952 var tooltipBehavior = null;
88953 var history = context.history();
88954 var key = uiCmd('⌘S');
88955 var _numChanges = 0;
88957 function isSaving() {
88958 var mode = context.mode();
88959 return mode && mode.id === 'save';
88962 function isDisabled() {
88963 return _numChanges === 0 || isSaving();
88966 function save(d3_event) {
88967 d3_event.preventDefault();
88969 if (!context.inIntro() && !isSaving() && history.hasChanges()) {
88970 context.enter(modeSave(context));
88974 function bgColor() {
88977 if (_numChanges === 0) {
88979 } else if (_numChanges <= 50) {
88980 step = _numChanges / 50;
88981 return d3_interpolateRgb('#fff', '#ff8')(step); // white -> yellow
88983 step = Math.min((_numChanges - 50) / 50, 1.0);
88984 return d3_interpolateRgb('#ff8', '#f88')(step); // yellow -> red
88988 function updateCount() {
88989 var val = history.difference().summary().length;
88990 if (val === _numChanges) return;
88993 if (tooltipBehavior) {
88994 tooltipBehavior.title(_t.html(_numChanges > 0 ? 'save.help' : 'save.no_changes')).keys([key]);
88998 button.classed('disabled', isDisabled()).style('background', bgColor());
88999 button.select('span.count').html(_numChanges);
89003 tool.render = function (selection) {
89004 tooltipBehavior = uiTooltip().placement('bottom').title(_t.html('save.no_changes')).keys([key]).scrollContainer(context.container().select('.top-toolbar'));
89005 var lastPointerUpType;
89006 button = selection.append('button').attr('class', 'save disabled bar-button').on('pointerup', function (d3_event) {
89007 lastPointerUpType = d3_event.pointerType;
89008 }).on('click', function (d3_event) {
89011 if (_numChanges === 0 && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
89012 // there are no tooltips for touch interactions so flash feedback instead
89013 context.ui().flash.duration(2000).iconName('#iD-icon-save').iconClass('disabled').label(_t.html('save.no_changes'))();
89016 lastPointerUpType = null;
89017 }).call(tooltipBehavior);
89018 button.call(svgIcon('#iD-icon-save'));
89019 button.append('span').attr('class', 'count').attr('aria-hidden', 'true').html('0');
89021 context.keybinding().on(key, save, true);
89022 context.history().on('change.save', updateCount);
89023 context.on('enter.save', function () {
89025 button.classed('disabled', isDisabled());
89028 button.call(tooltipBehavior.hide);
89034 tool.uninstall = function () {
89035 context.keybinding().off(key, true);
89036 context.history().on('change.save', null);
89037 context.on('enter.save', null);
89039 tooltipBehavior = null;
89045 function uiToolSidebarToggle(context) {
89047 id: 'sidebar_toggle',
89048 label: _t.html('toolbar.inspect')
89051 tool.render = function (selection) {
89052 selection.append('button').attr('class', 'bar-button').on('click', function () {
89053 context.ui().sidebar.toggle();
89054 }).call(uiTooltip().placement('bottom').title(_t.html('sidebar.tooltip')).keys([_t('sidebar.key')]).scrollContainer(context.container().select('.top-toolbar'))).call(svgIcon('#iD-icon-sidebar-' + (_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')));
89060 function uiToolUndoRedo(context) {
89063 label: _t.html('toolbar.undo_redo')
89068 action: function action() {
89071 annotation: function annotation() {
89072 return context.history().undoAnnotation();
89074 icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')
89078 action: function action() {
89081 annotation: function annotation() {
89082 return context.history().redoAnnotation();
89084 icon: 'iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'undo' : 'redo')
89087 function editable() {
89088 return context.mode() && context.mode().id !== 'save' && context.map().editableDataEnabled(true
89089 /* ignore min zoom */
89093 tool.render = function (selection) {
89094 var tooltipBehavior = uiTooltip().placement('bottom').title(function (d) {
89095 return d.annotation() ? _t.html(d.id + '.tooltip', {
89096 action: d.annotation()
89097 }) : _t.html(d.id + '.nothing');
89098 }).keys(function (d) {
89100 }).scrollContainer(context.container().select('.top-toolbar'));
89101 var lastPointerUpType;
89102 var buttons = selection.selectAll('button').data(commands).enter().append('button').attr('class', function (d) {
89103 return 'disabled ' + d.id + '-button bar-button';
89104 }).on('pointerup', function (d3_event) {
89105 // `pointerup` is always called before `click`
89106 lastPointerUpType = d3_event.pointerType;
89107 }).on('click', function (d3_event, d) {
89108 d3_event.preventDefault();
89109 var annotation = d.annotation();
89111 if (editable() && annotation) {
89115 if (editable() && (lastPointerUpType === 'touch' || lastPointerUpType === 'pen')) {
89116 // there are no tooltips for touch interactions so flash feedback instead
89117 var text = annotation ? _t(d.id + '.tooltip', {
89119 }) : _t(d.id + '.nothing');
89120 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass(annotation ? '' : 'disabled').label(text)();
89123 lastPointerUpType = null;
89124 }).call(tooltipBehavior);
89125 buttons.each(function (d) {
89126 select(this).call(svgIcon('#' + d.icon));
89128 context.keybinding().on(commands[0].cmd, function (d3_event) {
89129 d3_event.preventDefault();
89130 if (editable()) commands[0].action();
89131 }).on(commands[1].cmd, function (d3_event) {
89132 d3_event.preventDefault();
89133 if (editable()) commands[1].action();
89136 var debouncedUpdate = debounce(update, 500, {
89141 context.map().on('move.undo_redo', debouncedUpdate).on('drawn.undo_redo', debouncedUpdate);
89142 context.history().on('change.undo_redo', function (difference) {
89143 if (difference) update();
89145 context.on('enter.undo_redo', update);
89147 function update() {
89148 buttons.classed('disabled', function (d) {
89149 return !editable() || !d.annotation();
89150 }).each(function () {
89151 var selection = select(this);
89153 if (!selection.select('.tooltip.in').empty()) {
89154 selection.call(tooltipBehavior.updateContent);
89160 tool.uninstall = function () {
89161 context.keybinding().off(commands[0].cmd).off(commands[1].cmd);
89162 context.map().on('move.undo_redo', null).on('drawn.undo_redo', null);
89163 context.history().on('change.undo_redo', null);
89164 context.on('enter.undo_redo', null);
89170 function uiTopToolbar(context) {
89171 var sidebarToggle = uiToolSidebarToggle(context),
89172 modes = uiToolOldDrawModes(context),
89173 notes = uiToolNotes(context),
89174 undoRedo = uiToolUndoRedo(context),
89175 save = uiToolSave(context);
89177 function notesEnabled() {
89178 var noteLayer = context.layers().layer('notes');
89179 return noteLayer && noteLayer.enabled();
89182 function topToolbar(bar) {
89183 bar.on('wheel.topToolbar', function (d3_event) {
89184 if (!d3_event.deltaX) {
89185 // translate vertical scrolling into horizontal scrolling in case
89186 // the user doesn't have an input device that can scroll horizontally
89187 bar.node().scrollLeft += d3_event.deltaY;
89191 var debouncedUpdate = debounce(update, 500, {
89196 context.layers().on('change.topToolbar', debouncedUpdate);
89199 function update() {
89200 var tools = [sidebarToggle, 'spacer', modes];
89201 tools.push('spacer');
89203 if (notesEnabled()) {
89204 tools = tools.concat([notes, 'spacer']);
89207 tools = tools.concat([undoRedo, save]);
89208 var toolbarItems = bar.selectAll('.toolbar-item').data(tools, function (d) {
89211 toolbarItems.exit().each(function (d) {
89216 var itemsEnter = toolbarItems.enter().append('div').attr('class', function (d) {
89217 var classes = 'toolbar-item ' + (d.id || d).replace('_', '-');
89218 if (d.klass) classes += ' ' + d.klass;
89221 var actionableItems = itemsEnter.filter(function (d) {
89222 return d !== 'spacer';
89224 actionableItems.append('div').attr('class', 'item-content').each(function (d) {
89225 select(this).call(d.render, bar);
89227 actionableItems.append('div').attr('class', 'item-label').html(function (d) {
89236 var sawVersion = null;
89237 var isNewVersion = false;
89238 var isNewUser = false;
89239 function uiVersion(context) {
89240 var currVersion = context.version;
89241 var matchedVersion = currVersion.match(/\d+\.\d+\.\d+.*/);
89243 if (sawVersion === null && matchedVersion !== null) {
89244 if (corePreferences('sawVersion')) {
89246 isNewVersion = corePreferences('sawVersion') !== currVersion && currVersion.indexOf('-') === -1;
89249 isNewVersion = true;
89252 corePreferences('sawVersion', currVersion);
89253 sawVersion = currVersion;
89256 return function (selection) {
89257 selection.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD').html(currVersion); // only show new version indicator to users that have used iD before
89259 if (isNewVersion && !isNewUser) {
89260 selection.append('a').attr('class', 'badge').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/release/CHANGELOG.md#whats-new').call(svgIcon('#maki-gift-11')).call(uiTooltip().title(_t.html('version.whats_new', {
89261 version: currVersion
89262 })).placement('top').scrollContainer(context.container().select('.main-footer-wrap')));
89267 function uiZoom(context) {
89270 icon: 'iD-icon-plus',
89271 title: _t.html('zoom.in'),
89273 disabled: function disabled() {
89274 return !context.map().canZoomIn();
89276 disabledTitle: _t.html('zoom.disabled.in'),
89280 icon: 'iD-icon-minus',
89281 title: _t.html('zoom.out'),
89283 disabled: function disabled() {
89284 return !context.map().canZoomOut();
89286 disabledTitle: _t.html('zoom.disabled.out'),
89290 function zoomIn(d3_event) {
89291 if (d3_event.shiftKey) return;
89292 d3_event.preventDefault();
89293 context.map().zoomIn();
89296 function zoomOut(d3_event) {
89297 if (d3_event.shiftKey) return;
89298 d3_event.preventDefault();
89299 context.map().zoomOut();
89302 function zoomInFurther(d3_event) {
89303 if (d3_event.shiftKey) return;
89304 d3_event.preventDefault();
89305 context.map().zoomInFurther();
89308 function zoomOutFurther(d3_event) {
89309 if (d3_event.shiftKey) return;
89310 d3_event.preventDefault();
89311 context.map().zoomOutFurther();
89314 return function (selection) {
89315 var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function (d) {
89316 if (d.disabled()) {
89317 return d.disabledTitle;
89321 }).keys(function (d) {
89324 var lastPointerUpType;
89325 var buttons = selection.selectAll('button').data(zooms).enter().append('button').attr('class', function (d) {
89327 }).on('pointerup.editor', function (d3_event) {
89328 lastPointerUpType = d3_event.pointerType;
89329 }).on('click.editor', function (d3_event, d) {
89330 if (!d.disabled()) {
89331 d.action(d3_event);
89332 } else if (lastPointerUpType === 'touch' || lastPointerUpType === 'pen') {
89333 context.ui().flash.duration(2000).iconName('#' + d.icon).iconClass('disabled').label(d.disabledTitle)();
89336 lastPointerUpType = null;
89337 }).call(tooltipBehavior);
89338 buttons.each(function (d) {
89339 select(this).call(svgIcon('#' + d.icon, 'light'));
89341 utilKeybinding.plusKeys.forEach(function (key) {
89342 context.keybinding().on([key], zoomIn);
89343 context.keybinding().on([uiCmd('⌥' + key)], zoomInFurther);
89345 utilKeybinding.minusKeys.forEach(function (key) {
89346 context.keybinding().on([key], zoomOut);
89347 context.keybinding().on([uiCmd('⌥' + key)], zoomOutFurther);
89350 function updateButtonStates() {
89351 buttons.classed('disabled', function (d) {
89352 return d.disabled();
89353 }).each(function () {
89354 var selection = select(this);
89356 if (!selection.select('.tooltip.in').empty()) {
89357 selection.call(tooltipBehavior.updateContent);
89362 updateButtonStates();
89363 context.map().on('move.uiZoom', updateButtonStates);
89367 function uiZoomToSelection(context) {
89368 function isDisabled() {
89369 var mode = context.mode();
89370 return !mode || !mode.zoomToSelected;
89373 var _lastPointerUpType;
89375 function pointerup(d3_event) {
89376 _lastPointerUpType = d3_event.pointerType;
89379 function click(d3_event) {
89380 d3_event.preventDefault();
89382 if (isDisabled()) {
89383 if (_lastPointerUpType === 'touch' || _lastPointerUpType === 'pen') {
89384 context.ui().flash.duration(2000).iconName('#iD-icon-framed-dot').iconClass('disabled').label(_t.html('inspector.zoom_to.no_selection'))();
89387 var mode = context.mode();
89389 if (mode && mode.zoomToSelected) {
89390 mode.zoomToSelected();
89394 _lastPointerUpType = null;
89397 return function (selection) {
89398 var tooltipBehavior = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(function () {
89399 if (isDisabled()) {
89400 return _t.html('inspector.zoom_to.no_selection');
89403 return _t.html('inspector.zoom_to.title');
89404 }).keys([_t('inspector.zoom_to.key')]);
89405 var button = selection.append('button').on('pointerup', pointerup).on('click', click).call(svgIcon('#iD-icon-framed-dot', 'light')).call(tooltipBehavior);
89407 function setEnabledState() {
89408 button.classed('disabled', isDisabled());
89410 if (!button.select('.tooltip.in').empty()) {
89411 button.call(tooltipBehavior.updateContent);
89415 context.on('enter.uiZoomToSelection', setEnabledState);
89420 function uiPane(id, context) {
89424 var _description = '';
89425 var _iconName = '';
89427 var _sections; // array of uiSection objects
89430 var _paneSelection = select(null);
89438 pane.label = function (val) {
89439 if (!arguments.length) return _label;
89444 pane.key = function (val) {
89445 if (!arguments.length) return _key;
89450 pane.description = function (val) {
89451 if (!arguments.length) return _description;
89452 _description = val;
89456 pane.iconName = function (val) {
89457 if (!arguments.length) return _iconName;
89462 pane.sections = function (val) {
89463 if (!arguments.length) return _sections;
89468 pane.selection = function () {
89469 return _paneSelection;
89472 function hidePane() {
89473 context.ui().togglePanes();
89476 pane.togglePane = function (d3_event) {
89477 if (d3_event) d3_event.preventDefault();
89479 _paneTooltip.hide();
89481 context.ui().togglePanes(!_paneSelection.classed('shown') ? _paneSelection : undefined);
89484 pane.renderToggleButton = function (selection) {
89485 if (!_paneTooltip) {
89486 _paneTooltip = uiTooltip().placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left').title(_description).keys([_key]);
89489 selection.append('button').on('click', pane.togglePane).call(svgIcon('#' + _iconName, 'light')).call(_paneTooltip);
89492 pane.renderContent = function (selection) {
89493 // override to fully customize content
89495 _sections.forEach(function (section) {
89496 selection.call(section.render);
89501 pane.renderPane = function (selection) {
89502 _paneSelection = selection.append('div').attr('class', 'fillL map-pane hide ' + id + '-pane').attr('pane', id);
89504 var heading = _paneSelection.append('div').attr('class', 'pane-heading');
89506 heading.append('h2').html(_label);
89507 heading.append('button').on('click', hidePane).call(svgIcon('#iD-icon-close'));
89509 _paneSelection.append('div').attr('class', 'pane-content').call(pane.renderContent);
89512 context.keybinding().on(_key, pane.togglePane);
89519 function uiSectionBackgroundDisplayOptions(context) {
89520 var section = uiSection('background-display-options', context).label(_t.html('background.display_options')).disclosureContent(renderDisclosureContent);
89522 var _detected = utilDetect();
89524 var _storedOpacity = corePreferences('background-opacity');
89528 var _maxVal = _detected.cssfilters ? 3 : 1;
89530 var _sliders = _detected.cssfilters ? ['brightness', 'contrast', 'saturation', 'sharpness'] : ['brightness'];
89533 brightness: _storedOpacity !== null ? +_storedOpacity : 1,
89539 function clamp(x, min, max) {
89540 return Math.max(min, Math.min(x, max));
89543 function updateValue(d, val) {
89544 val = clamp(val, _minVal, _maxVal);
89546 context.background()[d](val);
89548 if (d === 'brightness') {
89549 corePreferences('background-opacity', val);
89552 section.reRender();
89555 function renderDisclosureContent(selection) {
89556 var container = selection.selectAll('.display-options-container').data([0]);
89557 var containerEnter = container.enter().append('div').attr('class', 'display-options-container controls-list'); // add slider controls
89559 var slidersEnter = containerEnter.selectAll('.display-control').data(_sliders).enter().append('div').attr('class', function (d) {
89560 return 'display-control display-control-' + d;
89562 slidersEnter.append('h5').html(function (d) {
89563 return _t.html('background.' + d);
89564 }).append('span').attr('class', function (d) {
89565 return 'display-option-value display-option-value-' + d;
89567 var sildersControlEnter = slidersEnter.append('div').attr('class', 'control-wrap');
89568 sildersControlEnter.append('input').attr('class', function (d) {
89569 return 'display-option-input display-option-input-' + d;
89570 }).attr('type', 'range').attr('min', _minVal).attr('max', _maxVal).attr('step', '0.05').on('input', function (d3_event, d) {
89571 var val = select(this).property('value');
89573 if (!val && d3_event && d3_event.target) {
89574 val = d3_event.target.value;
89577 updateValue(d, val);
89579 sildersControlEnter.append('button').attr('title', _t('background.reset')).attr('class', function (d) {
89580 return 'display-option-reset display-option-reset-' + d;
89581 }).on('click', function (d3_event, d) {
89582 if (d3_event.button !== 0) return;
89584 }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo'))); // reset all button
89586 containerEnter.append('a').attr('class', 'display-option-resetlink').attr('href', '#').html(_t.html('background.reset_all')).on('click', function (d3_event) {
89587 d3_event.preventDefault();
89589 for (var i = 0; i < _sliders.length; i++) {
89590 updateValue(_sliders[i], 1);
89594 container = containerEnter.merge(container);
89595 container.selectAll('.display-option-input').property('value', function (d) {
89596 return _options[d];
89598 container.selectAll('.display-option-value').html(function (d) {
89599 return Math.floor(_options[d] * 100) + '%';
89601 container.selectAll('.display-option-reset').classed('disabled', function (d) {
89602 return _options[d] === 1;
89603 }); // first time only, set brightness if needed
89605 if (containerEnter.size() && _options.brightness !== 1) {
89606 context.background().brightness(_options.brightness);
89613 function uiSettingsCustomBackground() {
89614 var dispatch = dispatch$8('change');
89616 function render(selection) {
89617 // keep separate copies of original and current settings
89618 var _origSettings = {
89619 template: corePreferences('background-custom-template')
89621 var _currSettings = {
89622 template: corePreferences('background-custom-template')
89624 var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
89625 var modal = uiConfirm(selection).okButton();
89626 modal.classed('settings-modal settings-custom-background', true);
89627 modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_background.header'));
89628 var textSection = modal.select('.modal-section.message-text');
89629 var instructions = "".concat(_t.html('settings.custom_background.instructions.info'), "\n") + '\n' + "#### ".concat(_t.html('settings.custom_background.instructions.wms.tokens_label'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.wms.tokens.proj'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.wms.tokens.wkid'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.wms.tokens.dimensions'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.wms.tokens.bbox'), "\n") + '\n' + "#### ".concat(_t.html('settings.custom_background.instructions.tms.tokens_label'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.tms.tokens.xyz'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.tms.tokens.flipped_y'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.tms.tokens.switch'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.tms.tokens.quadtile'), "\n") + "* ".concat(_t.html('settings.custom_background.instructions.tms.tokens.scale_factor'), "\n") + '\n' + "#### ".concat(_t.html('settings.custom_background.instructions.example'), "\n") + "`".concat(example, "`");
89630 textSection.append('div').attr('class', 'instructions-template').html(marked_1(instructions));
89631 textSection.append('textarea').attr('class', 'field-template').attr('placeholder', _t('settings.custom_background.template.placeholder')).call(utilNoAuto).property('value', _currSettings.template); // insert a cancel button
89633 var buttonSection = modal.select('.modal-section.buttons');
89634 buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
89635 buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
89636 buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
89638 function isSaveDisabled() {
89640 } // restore the original template
89643 function clickCancel() {
89644 textSection.select('.field-template').property('value', _origSettings.template);
89645 corePreferences('background-custom-template', _origSettings.template);
89648 } // accept the current template
89651 function clickSave() {
89652 _currSettings.template = textSection.select('.field-template').property('value');
89653 corePreferences('background-custom-template', _currSettings.template);
89656 dispatch.call('change', this, _currSettings);
89660 return utilRebind(render, dispatch, 'on');
89663 function uiSectionBackgroundList(context) {
89664 var _backgroundList = select(null);
89666 var _customSource = context.background().findSource('custom');
89668 var _settingsCustomBackground = uiSettingsCustomBackground().on('change', customChanged);
89670 var section = uiSection('background-list', context).label(_t.html('background.backgrounds')).disclosureContent(renderDisclosureContent);
89672 function previousBackgroundID() {
89673 return corePreferences('background-last-used-toggle');
89676 function renderDisclosureContent(selection) {
89677 // the background list
89678 var container = selection.selectAll('.layer-background-list').data([0]);
89679 _backgroundList = container.enter().append('ul').attr('class', 'layer-list layer-background-list').attr('dir', 'auto').merge(container); // add minimap toggle below list
89681 var bgExtrasListEnter = selection.selectAll('.bg-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list bg-extras-list');
89682 var minimapLabelEnter = bgExtrasListEnter.append('li').attr('class', 'minimap-toggle-item').append('label').call(uiTooltip().title(_t.html('background.minimap.tooltip')).keys([_t('background.minimap.key')]).placement('top'));
89683 minimapLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89684 d3_event.preventDefault();
89685 uiMapInMap.toggle();
89687 minimapLabelEnter.append('span').html(_t.html('background.minimap.description'));
89688 var panelLabelEnter = bgExtrasListEnter.append('li').attr('class', 'background-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('background.panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.background.key'))]).placement('top'));
89689 panelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89690 d3_event.preventDefault();
89691 context.ui().info.toggle('background');
89693 panelLabelEnter.append('span').html(_t.html('background.panel.description'));
89694 var locPanelLabelEnter = bgExtrasListEnter.append('li').attr('class', 'location-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('background.location_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.location.key'))]).placement('top'));
89695 locPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
89696 d3_event.preventDefault();
89697 context.ui().info.toggle('location');
89699 locPanelLabelEnter.append('span').html(_t.html('background.location_panel.description')); // "Info / Report a Problem" link
89701 selection.selectAll('.imagery-faq').data([0]).enter().append('div').attr('class', 'imagery-faq').append('a').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).attr('href', 'https://github.com/openstreetmap/iD/blob/develop/FAQ.md#how-can-i-report-an-issue-with-background-imagery').append('span').html(_t.html('background.imagery_problem_faq'));
89703 _backgroundList.call(drawListItems, 'radio', function (d3_event, d) {
89704 chooseBackground(d);
89706 return !d.isHidden() && !d.overlay;
89710 function setTooltips(selection) {
89711 selection.each(function (d, i, nodes) {
89712 var item = select(this).select('label');
89713 var span = item.select('span');
89714 var placement = i < nodes.length / 2 ? 'bottom' : 'top';
89715 var description = d.description();
89716 var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
89717 item.call(uiTooltip().destroyAny);
89719 if (d.id === previousBackgroundID()) {
89720 item.call(uiTooltip().placement(placement).title('<div>' + _t.html('background.switch') + '</div>').keys([uiCmd('⌘' + _t('background.key'))]));
89721 } else if (description || isOverflowing) {
89722 item.call(uiTooltip().placement(placement).title(description || d.label()));
89727 function drawListItems(layerList, type, change, filter) {
89728 var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter).sort(function (a, b) {
89729 return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
89731 var layerLinks = layerList.selectAll('li') // We have to be a bit inefficient about reordering the list since
89732 // arrow key navigation of radio values likes to work in the order
89733 // they were added, not the display document order.
89734 .data(sources, function (d, i) {
89735 return d.id + '---' + i;
89737 layerLinks.exit().remove();
89738 var enter = layerLinks.enter().append('li').classed('layer-custom', function (d) {
89739 return d.id === 'custom';
89740 }).classed('best', function (d) {
89743 var label = enter.append('label');
89744 label.append('input').attr('type', type).attr('name', 'background-layer').attr('value', function (d) {
89746 }).on('change', change);
89747 label.append('span').html(function (d) {
89750 enter.filter(function (d) {
89751 return d.id === 'custom';
89752 }).append('button').attr('class', 'layer-browse').call(uiTooltip().title(_t.html('settings.custom_background.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
89753 d3_event.preventDefault();
89755 }).call(svgIcon('#iD-icon-more'));
89756 enter.filter(function (d) {
89758 }).append('div').attr('class', 'best').call(uiTooltip().title(_t.html('background.best_imagery')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).append('span').html('★');
89759 layerList.call(updateLayerSelections);
89762 function updateLayerSelections(selection) {
89763 function active(d) {
89764 return context.background().showsLayer(d);
89767 selection.selectAll('li').classed('active', active).classed('switch', function (d) {
89768 return d.id === previousBackgroundID();
89769 }).call(setTooltips).selectAll('input').property('checked', active);
89772 function chooseBackground(d) {
89773 if (d.id === 'custom' && !d.template()) {
89774 return editCustom();
89777 var previousBackground = context.background().baseLayerSource();
89778 corePreferences('background-last-used-toggle', previousBackground.id);
89779 corePreferences('background-last-used', d.id);
89780 context.background().baseLayerSource(d);
89783 function customChanged(d) {
89784 if (d && d.template) {
89785 _customSource.template(d.template);
89787 chooseBackground(_customSource);
89789 _customSource.template('');
89791 chooseBackground(context.background().findSource('none'));
89795 function editCustom() {
89796 context.container().call(_settingsCustomBackground);
89799 context.background().on('change.background_list', function () {
89800 _backgroundList.call(updateLayerSelections);
89802 context.map().on('move.background_list', debounce(function () {
89803 // layers in-view may have changed due to map move
89804 window.requestIdleCallback(section.reRender);
89809 function uiSectionBackgroundOffset(context) {
89810 var section = uiSection('background-offset', context).label(_t.html('background.fix_misalignment')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
89812 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
89814 var _directions = [['top', [0, -0.5]], ['left', [-0.5, 0]], ['right', [0.5, 0]], ['bottom', [0, 0.5]]];
89816 function updateValue() {
89817 var meters = geoOffsetToMeters(context.background().offset());
89818 var x = +meters[0].toFixed(2);
89819 var y = +meters[1].toFixed(2);
89820 context.container().selectAll('.nudge-inner-rect').select('input').classed('error', false).property('value', x + ', ' + y);
89821 context.container().selectAll('.nudge-reset').classed('disabled', function () {
89822 return x === 0 && y === 0;
89826 function resetOffset() {
89827 context.background().offset([0, 0]);
89831 function nudge(d) {
89832 context.background().nudge(d, context.map().zoom());
89836 function inputOffset() {
89837 var input = select(this);
89838 var d = input.node().value;
89839 if (d === '') return resetOffset();
89840 d = d.replace(/;/g, ',').split(',').map(function (n) {
89841 // if n is NaN, it will always get mapped to false.
89842 return !isNaN(n) && n;
89845 if (d.length !== 2 || !d[0] || !d[1]) {
89846 input.classed('error', true);
89850 context.background().offset(geoMetersToOffset(d));
89854 function dragOffset(d3_event) {
89855 if (d3_event.button !== 0) return;
89856 var origin = [d3_event.clientX, d3_event.clientY];
89857 var pointerId = d3_event.pointerId || 'mouse';
89858 context.container().append('div').attr('class', 'nudge-surface');
89859 select(window).on(_pointerPrefix + 'move.drag-bg-offset', pointermove).on(_pointerPrefix + 'up.drag-bg-offset', pointerup);
89861 if (_pointerPrefix === 'pointer') {
89862 select(window).on('pointercancel.drag-bg-offset', pointerup);
89865 function pointermove(d3_event) {
89866 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
89867 var latest = [d3_event.clientX, d3_event.clientY];
89868 var d = [-(origin[0] - latest[0]) / 4, -(origin[1] - latest[1]) / 4];
89873 function pointerup(d3_event) {
89874 if (pointerId !== (d3_event.pointerId || 'mouse')) return;
89875 if (d3_event.button !== 0) return;
89876 context.container().selectAll('.nudge-surface').remove();
89877 select(window).on('.drag-bg-offset', null);
89881 function renderDisclosureContent(selection) {
89882 var container = selection.selectAll('.nudge-container').data([0]);
89883 var containerEnter = container.enter().append('div').attr('class', 'nudge-container');
89884 containerEnter.append('div').attr('class', 'nudge-instructions').html(_t.html('background.offset'));
89885 var nudgeWrapEnter = containerEnter.append('div').attr('class', 'nudge-controls-wrap');
89886 var nudgeEnter = nudgeWrapEnter.append('div').attr('class', 'nudge-outer-rect').on(_pointerPrefix + 'down', dragOffset);
89887 nudgeEnter.append('div').attr('class', 'nudge-inner-rect').append('input').attr('type', 'text').on('change', inputOffset);
89888 nudgeWrapEnter.append('div').selectAll('button').data(_directions).enter().append('button').attr('class', function (d) {
89889 return d[0] + ' nudge';
89890 }).on('click', function (d3_event, d) {
89893 nudgeWrapEnter.append('button').attr('title', _t('background.reset')).attr('class', 'nudge-reset disabled').on('click', function (d3_event) {
89894 d3_event.preventDefault();
89896 }).call(svgIcon('#iD-icon-' + (_mainLocalizer.textDirection() === 'rtl' ? 'redo' : 'undo')));
89900 context.background().on('change.backgroundOffset-update', updateValue);
89904 function uiSectionOverlayList(context) {
89905 var section = uiSection('overlay-list', context).label(_t.html('background.overlays')).disclosureContent(renderDisclosureContent);
89907 var _overlayList = select(null);
89909 function setTooltips(selection) {
89910 selection.each(function (d, i, nodes) {
89911 var item = select(this).select('label');
89912 var span = item.select('span');
89913 var placement = i < nodes.length / 2 ? 'bottom' : 'top';
89914 var description = d.description();
89915 var isOverflowing = span.property('clientWidth') !== span.property('scrollWidth');
89916 item.call(uiTooltip().destroyAny);
89918 if (description || isOverflowing) {
89919 item.call(uiTooltip().placement(placement).title(description || d.name()));
89924 function updateLayerSelections(selection) {
89925 function active(d) {
89926 return context.background().showsLayer(d);
89929 selection.selectAll('li').classed('active', active).call(setTooltips).selectAll('input').property('checked', active);
89932 function chooseOverlay(d3_event, d) {
89933 d3_event.preventDefault();
89934 context.background().toggleOverlayLayer(d);
89936 _overlayList.call(updateLayerSelections);
89938 document.activeElement.blur();
89941 function drawListItems(layerList, type, change, filter) {
89942 var sources = context.background().sources(context.map().extent(), context.map().zoom(), true).filter(filter);
89943 var layerLinks = layerList.selectAll('li').data(sources, function (d) {
89946 layerLinks.exit().remove();
89947 var enter = layerLinks.enter().append('li');
89948 var label = enter.append('label');
89949 label.append('input').attr('type', type).attr('name', 'layers').on('change', change);
89950 label.append('span').html(function (d) {
89953 layerList.selectAll('li').sort(sortSources);
89954 layerList.call(updateLayerSelections);
89956 function sortSources(a, b) {
89957 return a.best() && !b.best() ? -1 : b.best() && !a.best() ? 1 : d3_descending(a.area(), b.area()) || d3_ascending(a.name(), b.name()) || 0;
89961 function renderDisclosureContent(selection) {
89962 var container = selection.selectAll('.layer-overlay-list').data([0]);
89963 _overlayList = container.enter().append('ul').attr('class', 'layer-list layer-overlay-list').attr('dir', 'auto').merge(container);
89965 _overlayList.call(drawListItems, 'checkbox', chooseOverlay, function (d) {
89966 return !d.isHidden() && d.overlay;
89970 context.map().on('move.overlay_list', debounce(function () {
89971 // layers in-view may have changed due to map move
89972 window.requestIdleCallback(section.reRender);
89977 function uiPaneBackground(context) {
89978 var backgroundPane = uiPane('background', context).key(_t('background.key')).label(_t.html('background.title')).description(_t.html('background.description')).iconName('iD-icon-layers').sections([uiSectionBackgroundList(context), uiSectionOverlayList(context), uiSectionBackgroundDisplayOptions(context), uiSectionBackgroundOffset(context)]);
89979 return backgroundPane;
89982 function uiPaneHelp(context) {
89983 var docKeys = [['help', ['welcome', 'open_data_h', 'open_data', 'before_start_h', 'before_start', 'open_source_h', 'open_source', 'open_source_help']], ['overview', ['navigation_h', 'navigation_drag', 'navigation_zoom', 'features_h', 'features', 'nodes_ways']], ['editing', ['select_h', 'select_left_click', 'select_right_click', 'select_space', 'multiselect_h', 'multiselect', 'multiselect_shift_click', 'multiselect_lasso', 'undo_redo_h', 'undo_redo', 'save_h', 'save', 'save_validation', 'upload_h', 'upload', 'backups_h', 'backups', 'keyboard_h', 'keyboard']], ['feature_editor', ['intro', 'definitions', 'type_h', 'type', 'type_picker', 'fields_h', 'fields_all_fields', 'fields_example', 'fields_add_field', 'tags_h', 'tags_all_tags', 'tags_resources']], ['points', ['intro', 'add_point_h', 'add_point', 'add_point_finish', 'move_point_h', 'move_point', 'delete_point_h', 'delete_point', 'delete_point_command']], ['lines', ['intro', 'add_line_h', 'add_line', 'add_line_draw', 'add_line_continue', 'add_line_finish', 'modify_line_h', 'modify_line_dragnode', 'modify_line_addnode', 'connect_line_h', 'connect_line', 'connect_line_display', 'connect_line_drag', 'connect_line_tag', 'disconnect_line_h', 'disconnect_line_command', 'move_line_h', 'move_line_command', 'move_line_connected', 'delete_line_h', 'delete_line', 'delete_line_command']], ['areas', ['intro', 'point_or_area_h', 'point_or_area', 'add_area_h', 'add_area_command', 'add_area_draw', 'add_area_continue', 'add_area_finish', 'square_area_h', 'square_area_command', 'modify_area_h', 'modify_area_dragnode', 'modify_area_addnode', 'delete_area_h', 'delete_area', 'delete_area_command']], ['relations', ['intro', 'edit_relation_h', 'edit_relation', 'edit_relation_add', 'edit_relation_delete', 'maintain_relation_h', 'maintain_relation', 'relation_types_h', 'multipolygon_h', 'multipolygon', 'multipolygon_create', 'multipolygon_merge', 'turn_restriction_h', 'turn_restriction', 'turn_restriction_field', 'turn_restriction_editing', 'route_h', 'route', 'route_add', 'boundary_h', 'boundary', 'boundary_add']], ['operations', ['intro', 'intro_2', 'straighten', 'orthogonalize', 'circularize', 'move', 'rotate', 'reflect', 'continue', 'reverse', 'disconnect', 'split', 'extract', 'merge', 'delete', 'downgrade', 'copy_paste']], ['notes', ['intro', 'add_note_h', 'add_note', 'place_note', 'move_note', 'update_note_h', 'update_note', 'save_note_h', 'save_note']], ['imagery', ['intro', 'sources_h', 'choosing', 'sources', 'offsets_h', 'offset', 'offset_change']], ['streetlevel', ['intro', 'using_h', 'using', 'photos', 'viewer']], ['gps', ['intro', 'survey', 'using_h', 'using', 'tracing', 'upload']], ['qa', ['intro', 'tools_h', 'tools', 'issues_h', 'issues']]];
89985 'help.help.open_data_h': 3,
89986 'help.help.before_start_h': 3,
89987 'help.help.open_source_h': 3,
89988 'help.overview.navigation_h': 3,
89989 'help.overview.features_h': 3,
89990 'help.editing.select_h': 3,
89991 'help.editing.multiselect_h': 3,
89992 'help.editing.undo_redo_h': 3,
89993 'help.editing.save_h': 3,
89994 'help.editing.upload_h': 3,
89995 'help.editing.backups_h': 3,
89996 'help.editing.keyboard_h': 3,
89997 'help.feature_editor.type_h': 3,
89998 'help.feature_editor.fields_h': 3,
89999 'help.feature_editor.tags_h': 3,
90000 'help.points.add_point_h': 3,
90001 'help.points.move_point_h': 3,
90002 'help.points.delete_point_h': 3,
90003 'help.lines.add_line_h': 3,
90004 'help.lines.modify_line_h': 3,
90005 'help.lines.connect_line_h': 3,
90006 'help.lines.disconnect_line_h': 3,
90007 'help.lines.move_line_h': 3,
90008 'help.lines.delete_line_h': 3,
90009 'help.areas.point_or_area_h': 3,
90010 'help.areas.add_area_h': 3,
90011 'help.areas.square_area_h': 3,
90012 'help.areas.modify_area_h': 3,
90013 'help.areas.delete_area_h': 3,
90014 'help.relations.edit_relation_h': 3,
90015 'help.relations.maintain_relation_h': 3,
90016 'help.relations.relation_types_h': 2,
90017 'help.relations.multipolygon_h': 3,
90018 'help.relations.turn_restriction_h': 3,
90019 'help.relations.route_h': 3,
90020 'help.relations.boundary_h': 3,
90021 'help.notes.add_note_h': 3,
90022 'help.notes.update_note_h': 3,
90023 'help.notes.save_note_h': 3,
90024 'help.imagery.sources_h': 3,
90025 'help.imagery.offsets_h': 3,
90026 'help.streetlevel.using_h': 3,
90027 'help.gps.using_h': 3,
90028 'help.qa.tools_h': 3,
90029 'help.qa.issues_h': 3
90030 }; // For each section, squash all the texts into a single markdown document
90032 var docs = docKeys.map(function (key) {
90033 var helpkey = 'help.' + key[0];
90034 var helpPaneReplacements = {
90035 version: context.version
90037 var text = key[1].reduce(function (all, part) {
90038 var subkey = helpkey + '.' + part;
90039 var depth = headings[subkey]; // is this subkey a heading?
90041 var hhh = depth ? Array(depth + 1).join('#') + ' ' : ''; // if so, prepend with some ##'s
90043 return all + hhh + helpHtml(subkey, helpPaneReplacements) + '\n\n';
90046 title: _t.html(helpkey + '.title'),
90047 content: marked_1(text.trim()) // use keyboard key styling for shortcuts
90048 .replace(/<code>/g, '<kbd>').replace(/<\/code>/g, '<\/kbd>')
90051 var helpPane = uiPane('help', context).key(_t('help.key')).label(_t.html('help.title')).description(_t.html('help.title')).iconName('iD-icon-help');
90053 helpPane.renderContent = function (content) {
90054 function clickHelp(d, i) {
90055 var rtl = _mainLocalizer.textDirection() === 'rtl';
90056 content.property('scrollTop', 0);
90057 helpPane.selection().select('.pane-heading h2').html(d.title);
90058 body.html(d.content);
90059 body.selectAll('a').attr('target', '_blank');
90060 menuItems.classed('selected', function (m) {
90061 return m.title === d.title;
90066 nav.call(drawNext).call(drawPrevious);
90068 nav.call(drawPrevious).call(drawNext);
90071 function drawNext(selection) {
90072 if (i < docs.length - 1) {
90073 var nextLink = selection.append('a').attr('href', '#').attr('class', 'next').on('click', function (d3_event) {
90074 d3_event.preventDefault();
90075 clickHelp(docs[i + 1], i + 1);
90077 nextLink.append('span').html(docs[i + 1].title).call(svgIcon(rtl ? '#iD-icon-backward' : '#iD-icon-forward', 'inline'));
90081 function drawPrevious(selection) {
90083 var prevLink = selection.append('a').attr('href', '#').attr('class', 'previous').on('click', function (d3_event) {
90084 d3_event.preventDefault();
90085 clickHelp(docs[i - 1], i - 1);
90087 prevLink.call(svgIcon(rtl ? '#iD-icon-forward' : '#iD-icon-backward', 'inline')).append('span').html(docs[i - 1].title);
90092 function clickWalkthrough(d3_event) {
90093 d3_event.preventDefault();
90094 if (context.inIntro()) return;
90095 context.container().call(uiIntro(context));
90096 context.ui().togglePanes();
90099 function clickShortcuts(d3_event) {
90100 d3_event.preventDefault();
90101 context.container().call(context.ui().shortcuts, true);
90104 var toc = content.append('ul').attr('class', 'toc');
90105 var menuItems = toc.selectAll('li').data(docs).enter().append('li').append('a').attr('href', '#').html(function (d) {
90107 }).on('click', function (d3_event, d) {
90108 d3_event.preventDefault();
90109 clickHelp(d, docs.indexOf(d));
90111 var shortcuts = toc.append('li').attr('class', 'shortcuts').call(uiTooltip().title(_t.html('shortcuts.tooltip')).keys(['?']).placement('top')).append('a').attr('href', '#').on('click', clickShortcuts);
90112 shortcuts.append('div').html(_t.html('shortcuts.title'));
90113 var walkthrough = toc.append('li').attr('class', 'walkthrough').append('a').attr('href', '#').on('click', clickWalkthrough);
90114 walkthrough.append('svg').attr('class', 'logo logo-walkthrough').append('use').attr('xlink:href', '#iD-logo-walkthrough');
90115 walkthrough.append('div').html(_t.html('splash.walkthrough'));
90116 var helpContent = content.append('div').attr('class', 'left-content');
90117 var body = helpContent.append('div').attr('class', 'body');
90118 var nav = helpContent.append('div').attr('class', 'nav');
90119 clickHelp(docs[0], 0);
90125 function uiSectionValidationIssues(id, severity, context) {
90127 var section = uiSection(id, context).label(function () {
90128 if (!_issues) return '';
90129 var issueCountText = _issues.length > 1000 ? '1000+' : String(_issues.length);
90130 return _t('inspector.title_count', {
90131 title: _t.html('issues.' + severity + 's.list_title'),
90132 count: issueCountText
90134 }).disclosureContent(renderDisclosureContent).shouldDisplay(function () {
90135 return _issues && _issues.length;
90138 function getOptions() {
90140 what: corePreferences('validate-what') || 'edited',
90141 where: corePreferences('validate-where') || 'all'
90143 } // get and cache the issues to display, unordered
90146 function reloadIssues() {
90147 _issues = context.validator().getIssuesBySeverity(getOptions())[severity];
90150 function renderDisclosureContent(selection) {
90151 var center = context.map().center();
90152 var graph = context.graph(); // sort issues by distance away from the center of the map
90154 var issues = _issues.map(function withDistance(issue) {
90155 var extent = issue.extent(graph);
90156 var dist = extent ? geoSphericalDistance(center, extent.center()) : 0;
90157 return Object.assign(issue, {
90160 }).sort(function byDistance(a, b) {
90161 return a.dist - b.dist;
90162 }); // cut off at 1000
90165 issues = issues.slice(0, 1000); //renderIgnoredIssuesReset(_warningsSelection);
90167 selection.call(drawIssuesList, issues);
90170 function drawIssuesList(selection, issues) {
90171 var list = selection.selectAll('.issues-list').data([0]);
90172 list = list.enter().append('ul').attr('class', 'layer-list issues-list ' + severity + 's-list').merge(list);
90173 var items = list.selectAll('li').data(issues, function (d) {
90177 items.exit().remove(); // Enter
90179 var itemsEnter = items.enter().append('li').attr('class', function (d) {
90180 return 'issue severity-' + d.severity;
90182 var labelsEnter = itemsEnter.append('button').attr('class', 'issue-label').on('click', function (d3_event, d) {
90183 context.validator().focusIssue(d);
90184 }).on('mouseover', function (d3_event, d) {
90185 utilHighlightEntities(d.entityIds, true, context);
90186 }).on('mouseout', function (d3_event, d) {
90187 utilHighlightEntities(d.entityIds, false, context);
90189 var textEnter = labelsEnter.append('span').attr('class', 'issue-text');
90190 textEnter.append('span').attr('class', 'issue-icon').each(function (d) {
90191 var iconName = '#iD-icon-' + (d.severity === 'warning' ? 'alert' : 'error');
90192 select(this).call(svgIcon(iconName));
90194 textEnter.append('span').attr('class', 'issue-message');
90198 .attr('class', 'issue-autofix')
90199 .each(function(d) {
90200 if (!d.autoFix) return;
90203 .attr('title', t('issues.fix_one.title'))
90204 .datum(d.autoFix) // set button datum to the autofix
90205 .attr('class', 'autofix action')
90206 .on('click', function(d3_event, d) {
90207 d3_event.preventDefault();
90208 d3_event.stopPropagation();
90209 var issuesEntityIDs = d.issue.entityIds;
90210 utilHighlightEntities(issuesEntityIDs.concat(d.entityIds), false, context);
90211 context.perform.apply(context, d.autoArgs);
90212 context.validator().validate();
90214 .call(svgIcon('#iD-icon-wrench'));
90219 items = items.merge(itemsEnter).order();
90220 items.selectAll('.issue-message').html(function (d) {
90221 return d.message(context);
90225 var canAutoFix = issues.filter(function(issue) { return issue.autoFix; });
90226 var autoFixAll = selection.selectAll('.autofix-all')
90227 .data(canAutoFix.length ? [0] : []);
90232 var autoFixAllEnter = autoFixAll.enter()
90233 .insert('div', '.issues-list')
90234 .attr('class', 'autofix-all');
90235 var linkEnter = autoFixAllEnter
90237 .attr('class', 'autofix-all-link')
90238 .attr('href', '#');
90241 .attr('class', 'autofix-all-link-text')
90242 .html(t.html('issues.fix_all.title'));
90245 .attr('class', 'autofix-all-link-icon')
90246 .call(svgIcon('#iD-icon-wrench'));
90247 if (severity === 'warning') {
90248 renderIgnoredIssuesReset(selection);
90251 autoFixAll = autoFixAll
90252 .merge(autoFixAllEnter);
90253 autoFixAll.selectAll('.autofix-all-link')
90254 .on('click', function() {
90255 context.pauseChangeDispatch();
90256 context.perform(actionNoop());
90257 canAutoFix.forEach(function(issue) {
90258 var args = issue.autoFix.autoArgs.slice(); // copy
90259 if (typeof args[args.length - 1] !== 'function') {
90262 args.push(t('issues.fix_all.annotation'));
90263 context.replace.apply(context, args);
90265 context.resumeChangeDispatch();
90266 context.validator().validate();
90271 context.validator().on('validated.uiSectionValidationIssues' + id, function () {
90272 window.requestIdleCallback(function () {
90274 section.reRender();
90277 context.map().on('move.uiSectionValidationIssues' + id, debounce(function () {
90278 window.requestIdleCallback(function () {
90279 if (getOptions().where === 'visible') {
90280 // must refetch issues if they are viewport-dependent
90282 } // always reload list to re-sort-by-distance
90285 section.reRender();
90291 function uiSectionValidationOptions(context) {
90292 var section = uiSection('issues-options', context).content(renderContent);
90294 function renderContent(selection) {
90295 var container = selection.selectAll('.issues-options-container').data([0]);
90296 container = container.enter().append('div').attr('class', 'issues-options-container').merge(container);
90299 values: ['edited', 'all']
90302 values: ['visible', 'all']
90304 var options = container.selectAll('.issues-option').data(data, function (d) {
90307 var optionsEnter = options.enter().append('div').attr('class', function (d) {
90308 return 'issues-option issues-option-' + d.key;
90310 optionsEnter.append('div').attr('class', 'issues-option-title').html(function (d) {
90311 return _t.html('issues.options.' + d.key + '.title');
90313 var valuesEnter = optionsEnter.selectAll('label').data(function (d) {
90314 return d.values.map(function (val) {
90320 }).enter().append('label');
90321 valuesEnter.append('input').attr('type', 'radio').attr('name', function (d) {
90322 return 'issues-option-' + d.key;
90323 }).attr('value', function (d) {
90325 }).property('checked', function (d) {
90326 return getOptions()[d.key] === d.value;
90327 }).on('change', function (d3_event, d) {
90328 updateOptionValue(d3_event, d.key, d.value);
90330 valuesEnter.append('span').html(function (d) {
90331 return _t.html('issues.options.' + d.key + '.' + d.value);
90335 function getOptions() {
90337 what: corePreferences('validate-what') || 'edited',
90339 where: corePreferences('validate-where') || 'all' // 'all', 'visible'
90344 function updateOptionValue(d3_event, d, val) {
90345 if (!val && d3_event && d3_event.target) {
90346 val = d3_event.target.value;
90349 corePreferences('validate-' + d, val);
90350 context.validator().validate();
90356 function uiSectionValidationRules(context) {
90358 var MAXSQUARE = 20;
90359 var DEFAULTSQUARE = 5; // see also unsquare_way.js
90361 var section = uiSection('issues-rules', context).disclosureContent(renderDisclosureContent).label(_t.html('issues.rules.title'));
90363 var _ruleKeys = context.validator().getRuleKeys().filter(function (key) {
90364 return key !== 'maprules';
90365 }).sort(function (key1, key2) {
90366 // alphabetize by localized title
90367 return _t('issues.' + key1 + '.title') < _t('issues.' + key2 + '.title') ? -1 : 1;
90370 function renderDisclosureContent(selection) {
90371 var container = selection.selectAll('.issues-rulelist-container').data([0]);
90372 var containerEnter = container.enter().append('div').attr('class', 'issues-rulelist-container');
90373 containerEnter.append('ul').attr('class', 'layer-list issue-rules-list');
90374 var ruleLinks = containerEnter.append('div').attr('class', 'issue-rules-links section-footer');
90375 ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
90376 d3_event.preventDefault();
90377 context.validator().disableRules(_ruleKeys);
90379 ruleLinks.append('a').attr('class', 'issue-rules-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
90380 d3_event.preventDefault();
90381 context.validator().disableRules([]);
90384 container = container.merge(containerEnter);
90385 container.selectAll('.issue-rules-list').call(drawListItems, _ruleKeys, 'checkbox', 'rule', toggleRule, isRuleEnabled);
90388 function drawListItems(selection, data, type, name, change, active) {
90389 var items = selection.selectAll('li').data(data); // Exit
90391 items.exit().remove(); // Enter
90393 var enter = items.enter().append('li');
90395 if (name === 'rule') {
90396 enter.call(uiTooltip().title(function (d) {
90397 return _t.html('issues.' + d + '.tip');
90398 }).placement('top'));
90401 var label = enter.append('label');
90402 label.append('input').attr('type', type).attr('name', name).on('change', change);
90403 label.append('span').html(function (d) {
90406 if (d === 'unsquare_way') {
90407 params.val = '<span class="square-degrees"></span>';
90410 return _t.html('issues.' + d + '.title', params);
90413 items = items.merge(enter);
90414 items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false); // user-configurable square threshold
90416 var degStr = corePreferences('validate-square-degrees');
90418 if (degStr === null) {
90419 degStr = DEFAULTSQUARE.toString();
90422 var span = items.selectAll('.square-degrees');
90423 var input = span.selectAll('.square-degrees-input').data([0]); // enter / update
90425 input.enter().append('input').attr('type', 'number').attr('min', MINSQUARE.toString()).attr('max', MAXSQUARE.toString()).attr('step', '0.5').attr('class', 'square-degrees-input').call(utilNoAuto).on('click', function (d3_event) {
90426 d3_event.preventDefault();
90427 d3_event.stopPropagation();
90429 }).on('keyup', function (d3_event) {
90430 if (d3_event.keyCode === 13) {
90435 }).on('blur', changeSquare).merge(input).property('value', degStr);
90438 function changeSquare() {
90439 var input = select(this);
90440 var degStr = utilGetSetValue(input).trim();
90441 var degNum = parseFloat(degStr, 10);
90443 if (!isFinite(degNum)) {
90444 degNum = DEFAULTSQUARE;
90445 } else if (degNum > MAXSQUARE) {
90446 degNum = MAXSQUARE;
90447 } else if (degNum < MINSQUARE) {
90448 degNum = MINSQUARE;
90451 degNum = Math.round(degNum * 10) / 10; // round to 1 decimal
90453 degStr = degNum.toString();
90454 input.property('value', degStr);
90455 corePreferences('validate-square-degrees', degStr);
90456 context.validator().revalidateUnsquare();
90459 function isRuleEnabled(d) {
90460 return context.validator().isRuleEnabled(d);
90463 function toggleRule(d3_event, d) {
90464 context.validator().toggleRule(d);
90467 context.validator().on('validated.uiSectionValidationRules', function () {
90468 window.requestIdleCallback(section.reRender);
90473 function uiSectionValidationStatus(context) {
90474 var section = uiSection('issues-status', context).content(renderContent).shouldDisplay(function () {
90475 var issues = context.validator().getIssues(getOptions());
90476 return issues.length === 0;
90479 function getOptions() {
90481 what: corePreferences('validate-what') || 'edited',
90482 where: corePreferences('validate-where') || 'all'
90486 function renderContent(selection) {
90487 var box = selection.selectAll('.box').data([0]);
90488 var boxEnter = box.enter().append('div').attr('class', 'box');
90489 boxEnter.append('div').call(svgIcon('#iD-icon-apply', 'pre-text'));
90490 var noIssuesMessage = boxEnter.append('span');
90491 noIssuesMessage.append('strong').attr('class', 'message');
90492 noIssuesMessage.append('br');
90493 noIssuesMessage.append('span').attr('class', 'details');
90494 renderIgnoredIssuesReset(selection);
90495 setNoIssuesText(selection);
90498 function renderIgnoredIssuesReset(selection) {
90499 var ignoredIssues = context.validator().getIssues({
90502 includeDisabledRules: true,
90503 includeIgnored: 'only'
90505 var resetIgnored = selection.selectAll('.reset-ignored').data(ignoredIssues.length ? [0] : []); // exit
90507 resetIgnored.exit().remove(); // enter
90509 var resetIgnoredEnter = resetIgnored.enter().append('div').attr('class', 'reset-ignored section-footer');
90510 resetIgnoredEnter.append('a').attr('href', '#'); // update
90512 resetIgnored = resetIgnored.merge(resetIgnoredEnter);
90513 resetIgnored.select('a').html(_t('inspector.title_count', {
90514 title: _t.html('issues.reset_ignored'),
90515 count: ignoredIssues.length
90517 resetIgnored.on('click', function (d3_event) {
90518 d3_event.preventDefault();
90519 context.validator().resetIgnoredIssues();
90523 function setNoIssuesText(selection) {
90524 var opts = getOptions();
90526 function checkForHiddenIssues(cases) {
90527 for (var type in cases) {
90528 var hiddenOpts = cases[type];
90529 var hiddenIssues = context.validator().getIssues(hiddenOpts);
90531 if (hiddenIssues.length) {
90532 selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.' + type, {
90533 count: hiddenIssues.length.toString()
90539 selection.select('.box .details').html(_t.html('issues.no_issues.hidden_issues.none'));
90544 if (opts.what === 'edited' && opts.where === 'visible') {
90545 messageType = 'edits_in_view';
90546 checkForHiddenIssues({
90558 includeDisabledRules: 'only'
90560 everything_else_elsewhere: {
90564 disabled_rules_elsewhere: {
90567 includeDisabledRules: 'only'
90572 includeIgnored: 'only'
90574 ignored_issues_elsewhere: {
90577 includeIgnored: 'only'
90580 } else if (opts.what === 'edited' && opts.where === 'all') {
90581 messageType = 'edits';
90582 checkForHiddenIssues({
90590 includeDisabledRules: 'only'
90595 includeIgnored: 'only'
90598 } else if (opts.what === 'all' && opts.where === 'visible') {
90599 messageType = 'everything_in_view';
90600 checkForHiddenIssues({
90608 includeDisabledRules: 'only'
90610 disabled_rules_elsewhere: {
90613 includeDisabledRules: 'only'
90618 includeIgnored: 'only'
90620 ignored_issues_elsewhere: {
90623 includeIgnored: 'only'
90626 } else if (opts.what === 'all' && opts.where === 'all') {
90627 messageType = 'everything';
90628 checkForHiddenIssues({
90632 includeDisabledRules: 'only'
90637 includeIgnored: 'only'
90642 if (opts.what === 'edited' && context.history().difference().summary().length === 0) {
90643 messageType = 'no_edits';
90646 selection.select('.box .message').html(_t.html('issues.no_issues.message.' + messageType));
90649 context.validator().on('validated.uiSectionValidationStatus', function () {
90650 window.requestIdleCallback(section.reRender);
90652 context.map().on('move.uiSectionValidationStatus', debounce(function () {
90653 window.requestIdleCallback(section.reRender);
90658 function uiPaneIssues(context) {
90659 var issuesPane = uiPane('issues', context).key(_t('issues.key')).label(_t.html('issues.title')).description(_t.html('issues.title')).iconName('iD-icon-alert').sections([uiSectionValidationOptions(context), uiSectionValidationStatus(context), uiSectionValidationIssues('issues-errors', 'error', context), uiSectionValidationIssues('issues-warnings', 'warning', context), uiSectionValidationRules(context)]);
90663 function uiSettingsCustomData(context) {
90664 var dispatch = dispatch$8('change');
90666 function render(selection) {
90667 var dataLayer = context.layers().layer('data'); // keep separate copies of original and current settings
90669 var _origSettings = {
90670 fileList: dataLayer && dataLayer.fileList() || null,
90671 url: corePreferences('settings-custom-data-url')
90673 var _currSettings = {
90674 fileList: dataLayer && dataLayer.fileList() || null,
90675 url: corePreferences('settings-custom-data-url')
90676 }; // var example = 'https://{switch:a,b,c}.tile.openstreetmap.org/{zoom}/{x}/{y}.png';
90678 var modal = uiConfirm(selection).okButton();
90679 modal.classed('settings-modal settings-custom-data', true);
90680 modal.select('.modal-section.header').append('h3').html(_t.html('settings.custom_data.header'));
90681 var textSection = modal.select('.modal-section.message-text');
90682 textSection.append('pre').attr('class', 'instructions-file').html(_t.html('settings.custom_data.file.instructions'));
90683 textSection.append('input').attr('class', 'field-file').attr('type', 'file').property('files', _currSettings.fileList) // works for all except IE11
90684 .on('change', function (d3_event) {
90685 var files = d3_event.target.files;
90687 if (files && files.length) {
90688 _currSettings.url = '';
90689 textSection.select('.field-url').property('value', '');
90690 _currSettings.fileList = files;
90692 _currSettings.fileList = null;
90695 textSection.append('h4').html(_t.html('settings.custom_data.or'));
90696 textSection.append('pre').attr('class', 'instructions-url').html(_t.html('settings.custom_data.url.instructions'));
90697 textSection.append('textarea').attr('class', 'field-url').attr('placeholder', _t('settings.custom_data.url.placeholder')).call(utilNoAuto).property('value', _currSettings.url); // insert a cancel button
90699 var buttonSection = modal.select('.modal-section.buttons');
90700 buttonSection.insert('button', '.ok-button').attr('class', 'button cancel-button secondary-action').html(_t.html('confirm.cancel'));
90701 buttonSection.select('.cancel-button').on('click.cancel', clickCancel);
90702 buttonSection.select('.ok-button').attr('disabled', isSaveDisabled).on('click.save', clickSave);
90704 function isSaveDisabled() {
90706 } // restore the original url
90709 function clickCancel() {
90710 textSection.select('.field-url').property('value', _origSettings.url);
90711 corePreferences('settings-custom-data-url', _origSettings.url);
90714 } // accept the current url
90717 function clickSave() {
90718 _currSettings.url = textSection.select('.field-url').property('value').trim(); // one or the other but not both
90720 if (_currSettings.url) {
90721 _currSettings.fileList = null;
90724 if (_currSettings.fileList) {
90725 _currSettings.url = '';
90728 corePreferences('settings-custom-data-url', _currSettings.url);
90731 dispatch.call('change', this, _currSettings);
90735 return utilRebind(render, dispatch, 'on');
90738 function uiSectionDataLayers(context) {
90739 var settingsCustomData = uiSettingsCustomData(context).on('change', customChanged);
90740 var layers = context.layers();
90741 var section = uiSection('data-layers', context).label(_t.html('map_data.data_layers')).disclosureContent(renderDisclosureContent);
90743 function renderDisclosureContent(selection) {
90744 var container = selection.selectAll('.data-layer-container').data([0]);
90745 container.enter().append('div').attr('class', 'data-layer-container').merge(container).call(drawOsmItems).call(drawQAItems).call(drawCustomDataItems).call(drawVectorItems) // Beta - Detroit mapping challenge
90746 .call(drawPanelItems);
90749 function showsLayer(which) {
90750 var layer = layers.layer(which);
90753 return layer.enabled();
90759 function setLayer(which, enabled) {
90760 // Don't allow layer changes while drawing - #6584
90761 var mode = context.mode();
90762 if (mode && /^draw/.test(mode.id)) return;
90763 var layer = layers.layer(which);
90766 layer.enabled(enabled);
90768 if (!enabled && (which === 'osm' || which === 'notes')) {
90769 context.enter(modeBrowse(context));
90774 function toggleLayer(which) {
90775 setLayer(which, !showsLayer(which));
90778 function drawOsmItems(selection) {
90779 var osmKeys = ['osm', 'notes'];
90780 var osmLayers = layers.all().filter(function (obj) {
90781 return osmKeys.indexOf(obj.id) !== -1;
90783 var ul = selection.selectAll('.layer-list-osm').data([0]);
90784 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-osm').merge(ul);
90785 var li = ul.selectAll('.list-item').data(osmLayers);
90786 li.exit().remove();
90787 var liEnter = li.enter().append('li').attr('class', function (d) {
90788 return 'list-item list-item-' + d.id;
90790 var labelEnter = liEnter.append('label').each(function (d) {
90791 if (d.id === 'osm') {
90792 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).keys([uiCmd('⌥' + _t('area_fill.wireframe.key'))]).placement('bottom'));
90794 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
90797 labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
90800 labelEnter.append('span').html(function (d) {
90801 return _t.html('map_data.layers.' + d.id + '.title');
90804 li.merge(liEnter).classed('active', function (d) {
90805 return d.layer.enabled();
90806 }).selectAll('input').property('checked', function (d) {
90807 return d.layer.enabled();
90811 function drawQAItems(selection) {
90812 var qaKeys = ['keepRight', 'improveOSM', 'osmose'];
90813 var qaLayers = layers.all().filter(function (obj) {
90814 return qaKeys.indexOf(obj.id) !== -1;
90816 var ul = selection.selectAll('.layer-list-qa').data([0]);
90817 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-qa').merge(ul);
90818 var li = ul.selectAll('.list-item').data(qaLayers);
90819 li.exit().remove();
90820 var liEnter = li.enter().append('li').attr('class', function (d) {
90821 return 'list-item list-item-' + d.id;
90823 var labelEnter = liEnter.append('label').each(function (d) {
90824 select(this).call(uiTooltip().title(_t.html('map_data.layers.' + d.id + '.tooltip')).placement('bottom'));
90826 labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
90829 labelEnter.append('span').html(function (d) {
90830 return _t.html('map_data.layers.' + d.id + '.title');
90833 li.merge(liEnter).classed('active', function (d) {
90834 return d.layer.enabled();
90835 }).selectAll('input').property('checked', function (d) {
90836 return d.layer.enabled();
90838 } // Beta feature - sample vector layers to support Detroit Mapping Challenge
90839 // https://github.com/osmus/detroit-mapping-challenge
90842 function drawVectorItems(selection) {
90843 var dataLayer = layers.layer('data');
90845 name: 'Detroit Neighborhoods/Parks',
90846 src: 'neighborhoods-parks',
90847 tooltip: 'Neighborhood boundaries and parks as compiled by City of Detroit in concert with community groups.',
90848 template: 'https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmur6x34562qp9iv1u3ksf-54hev,jonahadkins.cjksmqxdx33jj2wp90xd9x2md-4e5y2/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA'
90850 name: 'Detroit Composite POIs',
90851 src: 'composite-poi',
90852 tooltip: 'Fire Inspections, Business Licenses, and other public location data collated from the City of Detroit.',
90853 template: 'https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmm6a02sli31myxhsr7zf3-2sw8h/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA'
90855 name: 'Detroit All-The-Places POIs',
90856 src: 'alltheplaces-poi',
90857 tooltip: 'Public domain business location data created by web scrapers.',
90858 template: 'https://{switch:a,b,c,d}.tiles.mapbox.com/v4/jonahadkins.cjksmswgk340g2vo06p1w9w0j-8fjjc/{z}/{x}/{y}.vector.pbf?access_token=pk.eyJ1Ijoiam9uYWhhZGtpbnMiLCJhIjoiRlVVVkx3VSJ9.9sdVEK_B_VkEXPjssU5MqA'
90859 }]; // Only show this if the map is around Detroit..
90861 var detroit = geoExtent([-83.5, 42.1], [-82.8, 42.5]);
90862 var showVectorItems = context.map().zoom() > 9 && detroit.contains(context.map().center());
90863 var container = selection.selectAll('.vectortile-container').data(showVectorItems ? [0] : []);
90864 container.exit().remove();
90865 var containerEnter = container.enter().append('div').attr('class', 'vectortile-container');
90866 containerEnter.append('h4').attr('class', 'vectortile-header').html('Detroit Vector Tiles (Beta)');
90867 containerEnter.append('ul').attr('class', 'layer-list layer-list-vectortile');
90868 containerEnter.append('div').attr('class', 'vectortile-footer').append('a').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).attr('href', 'https://github.com/osmus/detroit-mapping-challenge').append('span').html('About these layers');
90869 container = container.merge(containerEnter);
90870 var ul = container.selectAll('.layer-list-vectortile');
90871 var li = ul.selectAll('.list-item').data(vtData);
90872 li.exit().remove();
90873 var liEnter = li.enter().append('li').attr('class', function (d) {
90874 return 'list-item list-item-' + d.src;
90876 var labelEnter = liEnter.append('label').each(function (d) {
90877 select(this).call(uiTooltip().title(d.tooltip).placement('top'));
90879 labelEnter.append('input').attr('type', 'radio').attr('name', 'vectortile').on('change', selectVTLayer);
90880 labelEnter.append('span').html(function (d) {
90884 li.merge(liEnter).classed('active', isVTLayerSelected).selectAll('input').property('checked', isVTLayerSelected);
90886 function isVTLayerSelected(d) {
90887 return dataLayer && dataLayer.template() === d.template;
90890 function selectVTLayer(d3_event, d) {
90891 corePreferences('settings-custom-data-url', d.template);
90894 dataLayer.template(d.template, d.src);
90895 dataLayer.enabled(true);
90900 function drawCustomDataItems(selection) {
90901 var dataLayer = layers.layer('data');
90902 var hasData = dataLayer && dataLayer.hasData();
90903 var showsData = hasData && dataLayer.enabled();
90904 var ul = selection.selectAll('.layer-list-data').data(dataLayer ? [0] : []); // Exit
90906 ul.exit().remove(); // Enter
90908 var ulEnter = ul.enter().append('ul').attr('class', 'layer-list layer-list-data');
90909 var liEnter = ulEnter.append('li').attr('class', 'list-item-data');
90910 var labelEnter = liEnter.append('label').call(uiTooltip().title(_t.html('map_data.layers.custom.tooltip')).placement('top'));
90911 labelEnter.append('input').attr('type', 'checkbox').on('change', function () {
90912 toggleLayer('data');
90914 labelEnter.append('span').html(_t.html('map_data.layers.custom.title'));
90915 liEnter.append('button').attr('class', 'open-data-options').call(uiTooltip().title(_t.html('settings.custom_data.tooltip')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
90916 d3_event.preventDefault();
90918 }).call(svgIcon('#iD-icon-more'));
90919 liEnter.append('button').attr('class', 'zoom-to-data').call(uiTooltip().title(_t.html('map_data.layers.custom.zoom')).placement(_mainLocalizer.textDirection() === 'rtl' ? 'right' : 'left')).on('click', function (d3_event) {
90920 if (select(this).classed('disabled')) return;
90921 d3_event.preventDefault();
90922 d3_event.stopPropagation();
90923 dataLayer.fitZoom();
90924 }).call(svgIcon('#iD-icon-framed-dot', 'monochrome')); // Update
90926 ul = ul.merge(ulEnter);
90927 ul.selectAll('.list-item-data').classed('active', showsData).selectAll('label').classed('deemphasize', !hasData).selectAll('input').property('disabled', !hasData).property('checked', showsData);
90928 ul.selectAll('button.zoom-to-data').classed('disabled', !hasData);
90931 function editCustom() {
90932 context.container().call(settingsCustomData);
90935 function customChanged(d) {
90936 var dataLayer = layers.layer('data');
90939 dataLayer.url(d.url);
90940 } else if (d && d.fileList) {
90941 dataLayer.fileList(d.fileList);
90945 function drawPanelItems(selection) {
90946 var panelsListEnter = selection.selectAll('.md-extras-list').data([0]).enter().append('ul').attr('class', 'layer-list md-extras-list');
90947 var historyPanelLabelEnter = panelsListEnter.append('li').attr('class', 'history-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('map_data.history_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.history.key'))]).placement('top'));
90948 historyPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90949 d3_event.preventDefault();
90950 context.ui().info.toggle('history');
90952 historyPanelLabelEnter.append('span').html(_t.html('map_data.history_panel.title'));
90953 var measurementPanelLabelEnter = panelsListEnter.append('li').attr('class', 'measurement-panel-toggle-item').append('label').call(uiTooltip().title(_t.html('map_data.measurement_panel.tooltip')).keys([uiCmd('⌘⇧' + _t('info_panels.measurement.key'))]).placement('top'));
90954 measurementPanelLabelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
90955 d3_event.preventDefault();
90956 context.ui().info.toggle('measurement');
90958 measurementPanelLabelEnter.append('span').html(_t.html('map_data.measurement_panel.title'));
90961 context.layers().on('change.uiSectionDataLayers', section.reRender);
90962 context.map().on('move.uiSectionDataLayers', debounce(function () {
90963 // Detroit layers may have moved in or out of view
90964 window.requestIdleCallback(section.reRender);
90969 function uiSectionMapFeatures(context) {
90970 var _features = context.features().keys();
90972 var section = uiSection('map-features', context).label(_t.html('map_data.map_features')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
90974 function renderDisclosureContent(selection) {
90975 var container = selection.selectAll('.layer-feature-list-container').data([0]);
90976 var containerEnter = container.enter().append('div').attr('class', 'layer-feature-list-container');
90977 containerEnter.append('ul').attr('class', 'layer-list layer-feature-list');
90978 var footer = containerEnter.append('div').attr('class', 'feature-list-links section-footer');
90979 footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.disable_all')).on('click', function (d3_event) {
90980 d3_event.preventDefault();
90981 context.features().disableAll();
90983 footer.append('a').attr('class', 'feature-list-link').attr('href', '#').html(_t.html('issues.enable_all')).on('click', function (d3_event) {
90984 d3_event.preventDefault();
90985 context.features().enableAll();
90988 container = container.merge(containerEnter);
90989 container.selectAll('.layer-feature-list').call(drawListItems, _features, 'checkbox', 'feature', clickFeature, showsFeature);
90992 function drawListItems(selection, data, type, name, change, active) {
90993 var items = selection.selectAll('li').data(data); // Exit
90995 items.exit().remove(); // Enter
90997 var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
90998 var tip = _t.html(name + '.' + d + '.tooltip');
91000 if (autoHiddenFeature(d)) {
91001 var msg = showsLayer('osm') ? _t.html('map_data.autohidden') : _t.html('map_data.osmhidden');
91002 tip += '<div>' + msg + '</div>';
91006 }).placement('top'));
91007 var label = enter.append('label');
91008 label.append('input').attr('type', type).attr('name', name).on('change', change);
91009 label.append('span').html(function (d) {
91010 return _t.html(name + '.' + d + '.description');
91013 items = items.merge(enter);
91014 items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', autoHiddenFeature);
91017 function autoHiddenFeature(d) {
91018 return context.features().autoHidden(d);
91021 function showsFeature(d) {
91022 return context.features().enabled(d);
91025 function clickFeature(d3_event, d) {
91026 context.features().toggle(d);
91029 function showsLayer(id) {
91030 var layer = context.layers().layer(id);
91031 return layer && layer.enabled();
91035 context.features().on('change.map_features', section.reRender);
91039 function uiSectionMapStyleOptions(context) {
91040 var section = uiSection('fill-area', context).label(_t.html('map_data.style_options')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
91042 function renderDisclosureContent(selection) {
91043 var container = selection.selectAll('.layer-fill-list').data([0]);
91044 container.enter().append('ul').attr('class', 'layer-list layer-fill-list').merge(container).call(drawListItems, context.map().areaFillOptions, 'radio', 'area_fill', setFill, isActiveFill);
91045 var container2 = selection.selectAll('.layer-visual-diff-list').data([0]);
91046 container2.enter().append('ul').attr('class', 'layer-list layer-visual-diff-list').merge(container2).call(drawListItems, ['highlight_edits'], 'checkbox', 'visual_diff', toggleHighlightEdited, function () {
91047 return context.surface().classed('highlight-edited');
91051 function drawListItems(selection, data, type, name, change, active) {
91052 var items = selection.selectAll('li').data(data); // Exit
91054 items.exit().remove(); // Enter
91056 var enter = items.enter().append('li').call(uiTooltip().title(function (d) {
91057 return _t.html(name + '.' + d + '.tooltip');
91058 }).keys(function (d) {
91059 var key = d === 'wireframe' ? _t('area_fill.wireframe.key') : null;
91060 if (d === 'highlight_edits') key = _t('map_data.highlight_edits.key');
91061 return key ? [key] : null;
91062 }).placement('top'));
91063 var label = enter.append('label');
91064 label.append('input').attr('type', type).attr('name', name).on('change', change);
91065 label.append('span').html(function (d) {
91066 return _t.html(name + '.' + d + '.description');
91069 items = items.merge(enter);
91070 items.classed('active', active).selectAll('input').property('checked', active).property('indeterminate', false);
91073 function isActiveFill(d) {
91074 return context.map().activeAreaFill() === d;
91077 function toggleHighlightEdited(d3_event) {
91078 d3_event.preventDefault();
91079 context.map().toggleHighlightEdited();
91082 function setFill(d3_event, d) {
91083 context.map().activeAreaFill(d);
91086 context.map().on('changeHighlighting.ui_style, changeAreaFill.ui_style', section.reRender);
91090 function uiSectionPhotoOverlays(context) {
91091 var layers = context.layers();
91092 var section = uiSection('photo-overlays', context).label(_t.html('photo_overlays.title')).disclosureContent(renderDisclosureContent).expandedByDefault(false);
91094 function renderDisclosureContent(selection) {
91095 var container = selection.selectAll('.photo-overlay-container').data([0]);
91096 container.enter().append('div').attr('class', 'photo-overlay-container').merge(container).call(drawPhotoItems).call(drawPhotoTypeItems).call(drawDateFilter).call(drawUsernameFilter);
91099 function drawPhotoItems(selection) {
91100 var photoKeys = context.photos().overlayLayerIDs();
91101 var photoLayers = layers.all().filter(function (obj) {
91102 return photoKeys.indexOf(obj.id) !== -1;
91104 var data = photoLayers.filter(function (obj) {
91105 return obj.layer.supported();
91108 function layerSupported(d) {
91109 return d.layer && d.layer.supported();
91112 function layerEnabled(d) {
91113 return layerSupported(d) && d.layer.enabled();
91116 var ul = selection.selectAll('.layer-list-photos').data([0]);
91117 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photos').merge(ul);
91118 var li = ul.selectAll('.list-item-photos').data(data);
91119 li.exit().remove();
91120 var liEnter = li.enter().append('li').attr('class', function (d) {
91121 var classes = 'list-item-photos list-item-' + d.id;
91123 if (d.id === 'mapillary-signs' || d.id === 'mapillary-map-features') {
91124 classes += ' indented';
91129 var labelEnter = liEnter.append('label').each(function (d) {
91131 if (d.id === 'mapillary-signs') titleID = 'mapillary.signs.tooltip';else if (d.id === 'mapillary') titleID = 'mapillary_images.tooltip';else if (d.id === 'openstreetcam') titleID = 'openstreetcam_images.tooltip';else titleID = d.id.replace(/-/g, '_') + '.tooltip';
91132 select(this).call(uiTooltip().title(_t.html(titleID)).placement('top'));
91134 labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91137 labelEnter.append('span').html(function (d) {
91139 if (id === 'mapillary-signs') id = 'photo_overlays.traffic_signs';
91140 return _t.html(id.replace(/-/g, '_') + '.title');
91143 li.merge(liEnter).classed('active', layerEnabled).selectAll('input').property('checked', layerEnabled);
91146 function drawPhotoTypeItems(selection) {
91147 var data = context.photos().allPhotoTypes();
91149 function typeEnabled(d) {
91150 return context.photos().showsPhotoType(d);
91153 var ul = selection.selectAll('.layer-list-photo-types').data([0]);
91154 ul.exit().remove();
91155 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-photo-types').merge(ul);
91156 var li = ul.selectAll('.list-item-photo-types').data(context.photos().shouldFilterByPhotoType() ? data : []);
91157 li.exit().remove();
91158 var liEnter = li.enter().append('li').attr('class', function (d) {
91159 return 'list-item-photo-types list-item-' + d;
91161 var labelEnter = liEnter.append('label').each(function (d) {
91162 select(this).call(uiTooltip().title(_t.html('photo_overlays.photo_type.' + d + '.tooltip')).placement('top'));
91164 labelEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event, d) {
91165 context.photos().togglePhotoType(d);
91167 labelEnter.append('span').html(function (d) {
91168 return _t.html('photo_overlays.photo_type.' + d + '.title');
91171 li.merge(liEnter).classed('active', typeEnabled).selectAll('input').property('checked', typeEnabled);
91174 function drawDateFilter(selection) {
91175 var data = context.photos().dateFilters();
91177 function filterEnabled(d) {
91178 return context.photos().dateFilterValue(d);
91181 var ul = selection.selectAll('.layer-list-date-filter').data([0]);
91182 ul.exit().remove();
91183 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-date-filter').merge(ul);
91184 var li = ul.selectAll('.list-item-date-filter').data(context.photos().shouldFilterByDate() ? data : []);
91185 li.exit().remove();
91186 var liEnter = li.enter().append('li').attr('class', 'list-item-date-filter');
91187 var labelEnter = liEnter.append('label').each(function (d) {
91188 select(this).call(uiTooltip().title(_t.html('photo_overlays.date_filter.' + d + '.tooltip')).placement('top'));
91190 labelEnter.append('span').html(function (d) {
91191 return _t.html('photo_overlays.date_filter.' + d + '.title');
91193 labelEnter.append('input').attr('type', 'date').attr('class', 'list-item-input').attr('placeholder', _t('units.year_month_day')).call(utilNoAuto).each(function (d) {
91194 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
91195 }).on('change', function (d3_event, d) {
91196 var value = utilGetSetValue(select(this)).trim();
91197 context.photos().setDateFilter(d, value, true); // reload the displayed dates
91199 li.selectAll('input').each(function (d) {
91200 utilGetSetValue(select(this), context.photos().dateFilterValue(d) || '');
91203 li = li.merge(liEnter).classed('active', filterEnabled);
91206 function drawUsernameFilter(selection) {
91207 function filterEnabled() {
91208 return context.photos().usernames();
91211 var ul = selection.selectAll('.layer-list-username-filter').data([0]);
91212 ul.exit().remove();
91213 ul = ul.enter().append('ul').attr('class', 'layer-list layer-list-username-filter').merge(ul);
91214 var li = ul.selectAll('.list-item-username-filter').data(context.photos().shouldFilterByUsername() ? ['username-filter'] : []);
91215 li.exit().remove();
91216 var liEnter = li.enter().append('li').attr('class', 'list-item-username-filter');
91217 var labelEnter = liEnter.append('label').each(function () {
91218 select(this).call(uiTooltip().title(_t.html('photo_overlays.username_filter.tooltip')).placement('top'));
91220 labelEnter.append('span').html(_t.html('photo_overlays.username_filter.title'));
91221 labelEnter.append('input').attr('type', 'text').attr('class', 'list-item-input').call(utilNoAuto).property('value', usernameValue).on('change', function () {
91222 var value = select(this).property('value');
91223 context.photos().setUsernameFilter(value, true);
91224 select(this).property('value', usernameValue);
91226 li.merge(liEnter).classed('active', filterEnabled);
91228 function usernameValue() {
91229 var usernames = context.photos().usernames();
91230 if (usernames) return usernames.join('; ');
91235 function toggleLayer(which) {
91236 setLayer(which, !showsLayer(which));
91239 function showsLayer(which) {
91240 var layer = layers.layer(which);
91243 return layer.enabled();
91249 function setLayer(which, enabled) {
91250 var layer = layers.layer(which);
91253 layer.enabled(enabled);
91257 context.layers().on('change.uiSectionPhotoOverlays', section.reRender);
91258 context.photos().on('change.uiSectionPhotoOverlays', section.reRender);
91262 function uiPaneMapData(context) {
91263 var mapDataPane = uiPane('map-data', context).key(_t('map_data.key')).label(_t.html('map_data.title')).description(_t.html('map_data.description')).iconName('iD-icon-data').sections([uiSectionDataLayers(context), uiSectionPhotoOverlays(context), uiSectionMapStyleOptions(context), uiSectionMapFeatures(context)]);
91264 return mapDataPane;
91267 function uiSectionPrivacy(context) {
91268 var section = uiSection('preferences-third-party', context).label(_t.html('preferences.privacy.title')).disclosureContent(renderDisclosureContent);
91270 var _showThirdPartyIcons = corePreferences('preferences.privacy.thirdpartyicons') || 'true';
91272 function renderDisclosureContent(selection) {
91274 var privacyOptionsListEnter = selection.selectAll('.privacy-options-list').data([0]).enter().append('ul').attr('class', 'layer-list privacy-options-list');
91275 var thirdPartyIconsEnter = privacyOptionsListEnter.append('li').attr('class', 'privacy-third-party-icons-item').append('label').call(uiTooltip().title(_t.html('preferences.privacy.third_party_icons.tooltip')).placement('bottom'));
91276 thirdPartyIconsEnter.append('input').attr('type', 'checkbox').on('change', function (d3_event) {
91277 d3_event.preventDefault();
91278 _showThirdPartyIcons = _showThirdPartyIcons === 'true' ? 'false' : 'true';
91279 corePreferences('preferences.privacy.thirdpartyicons', _showThirdPartyIcons);
91282 thirdPartyIconsEnter.append('span').html(_t.html('preferences.privacy.third_party_icons.description')); // Privacy Policy link
91284 selection.selectAll('.privacy-link').data([0]).enter().append('div').attr('class', 'privacy-link').append('a').attr('target', '_blank').call(svgIcon('#iD-icon-out-link', 'inline')).attr('href', 'https://github.com/openstreetmap/iD/blob/release/PRIVACY.md').append('span').html(_t.html('preferences.privacy.privacy_link'));
91287 function update() {
91288 selection.selectAll('.privacy-third-party-icons-item').classed('active', _showThirdPartyIcons === 'true').select('input').property('checked', _showThirdPartyIcons === 'true');
91295 function uiPanePreferences(context) {
91296 var preferencesPane = uiPane('preferences', context).key(_t('preferences.key')).label(_t.html('preferences.title')).description(_t.html('preferences.description')).iconName('fas-user-cog').sections([uiSectionPrivacy(context)]);
91297 return preferencesPane;
91300 function uiInit(context) {
91301 var _initCounter = 0;
91302 var _needWidth = {};
91304 var _lastPointerType;
91306 function render(container) {
91307 container.on('click.ui', function (d3_event) {
91308 // we're only concerned with the primary mouse button
91309 if (d3_event.button !== 0) return;
91310 if (!d3_event.composedPath) return; // some targets have default click events we don't want to override
91312 var isOkayTarget = d3_event.composedPath().some(function (node) {
91313 // we only care about element nodes
91314 return node.nodeType === 1 && ( // clicking <input> focuses it and/or changes a value
91315 node.nodeName === 'INPUT' || // clicking <label> affects its <input> by default
91316 node.nodeName === 'LABEL' || // clicking <a> opens a hyperlink by default
91317 node.nodeName === 'A');
91319 if (isOkayTarget) return; // disable double-tap-to-zoom on touchscreens
91321 d3_event.preventDefault();
91323 var detected = utilDetect(); // only WebKit supports gesture events
91325 if ('GestureEvent' in window && // Listening for gesture events on iOS 13.4+ breaks double-tapping,
91326 // but we only need to do this on desktop Safari anyway. – #7694
91327 !detected.isMobileWebKit) {
91328 // On iOS we disable pinch-to-zoom of the UI via the `touch-action`
91329 // CSS property, but on desktop Safari we need to manually cancel the
91330 // default gesture events.
91331 container.on('gesturestart.ui gesturechange.ui gestureend.ui', function (d3_event) {
91332 // disable pinch-to-zoom of the UI via multitouch trackpads on macOS Safari
91333 d3_event.preventDefault();
91337 if ('PointerEvent' in window) {
91338 select(window).on('pointerdown.ui pointerup.ui', function (d3_event) {
91339 var pointerType = d3_event.pointerType || 'mouse';
91341 if (_lastPointerType !== pointerType) {
91342 _lastPointerType = pointerType;
91343 container.attr('pointer', pointerType);
91347 _lastPointerType = 'mouse';
91348 container.attr('pointer', 'mouse');
91351 container.attr('lang', _mainLocalizer.localeCode()).attr('dir', _mainLocalizer.textDirection()); // setup fullscreen keybindings (no button shown at this time)
91353 container.call(uiFullScreen(context));
91354 var map = context.map();
91355 map.redrawEnable(false); // don't draw until we've set zoom/lat/long
91357 map.on('hitMinZoom.ui', function () {
91358 ui.flash.iconName('#iD-icon-no').label(_t.html('cannot_zoom'))();
91360 container.append('svg').attr('id', 'ideditor-defs').call(ui.svgDefs);
91361 container.append('div').attr('class', 'sidebar').call(ui.sidebar);
91362 var content = container.append('div').attr('class', 'main-content active'); // Top toolbar
91364 content.append('div').attr('class', 'top-toolbar-wrap').append('div').attr('class', 'top-toolbar fillD').call(uiTopToolbar(context));
91365 content.append('div').attr('class', 'main-map').attr('dir', 'ltr').call(map);
91366 var overMap = content.append('div').attr('class', 'over-map'); // HACK: Mobile Safari 14 likes to select anything selectable when long-
91367 // pressing, even if it's not targeted. This conflicts with long-pressing
91368 // to show the edit menu. We add a selectable offscreen element as the first
91369 // child to trick Safari into not showing the selection UI.
91371 overMap.append('div').attr('class', 'select-trap').text('t');
91372 overMap.call(uiMapInMap(context)).call(uiNotice(context));
91373 overMap.append('div').attr('class', 'spinner').call(uiSpinner(context)); // Map controls
91375 var controls = overMap.append('div').attr('class', 'map-controls');
91376 controls.append('div').attr('class', 'map-control zoombuttons').call(uiZoom(context));
91377 controls.append('div').attr('class', 'map-control zoom-to-selection-control').call(uiZoomToSelection(context));
91378 controls.append('div').attr('class', 'map-control geolocate-control').call(uiGeolocate(context));
91379 controls.on('wheel.mapControls', function (d3_event) {
91380 if (!d3_event.deltaX) {
91381 controls.node().scrollTop += d3_event.deltaY;
91384 // This should happen after map is initialized, as some require surface()
91386 var panes = overMap.append('div').attr('class', 'map-panes');
91387 var uiPanes = [uiPaneBackground(context), uiPaneMapData(context), uiPaneIssues(context), uiPanePreferences(context), uiPaneHelp(context)];
91388 uiPanes.forEach(function (pane) {
91389 controls.append('div').attr('class', 'map-control map-pane-control ' + pane.id + '-control').call(pane.renderToggleButton);
91390 panes.call(pane.renderPane);
91392 ui.info = uiInfo(context);
91393 overMap.call(ui.info);
91394 overMap.append('div').attr('class', 'photoviewer').classed('al', true) // 'al'=left, 'ar'=right
91395 .classed('hide', true).call(ui.photoviewer);
91396 overMap.append('div').attr('class', 'attribution-wrap').attr('dir', 'ltr').call(uiAttribution(context)); // Add footer
91398 var about = content.append('div').attr('class', 'map-footer');
91399 about.append('div').attr('class', 'api-status').call(uiStatus(context));
91400 var footer = about.append('div').attr('class', 'map-footer-bar fillD');
91401 footer.append('div').attr('class', 'flash-wrap footer-hide');
91402 var footerWrap = footer.append('div').attr('class', 'main-footer-wrap footer-show');
91403 footerWrap.append('div').attr('class', 'scale-block').call(uiScale(context));
91404 var aboutList = footerWrap.append('div').attr('class', 'info-block').append('ul').attr('class', 'map-footer-list');
91405 aboutList.append('li').attr('class', 'user-list').call(uiContributors(context));
91406 var apiConnections = context.apiConnections();
91408 if (apiConnections && apiConnections.length > 1) {
91409 aboutList.append('li').attr('class', 'source-switch').call(uiSourceSwitch(context).keys(apiConnections));
91412 aboutList.append('li').attr('class', 'issues-info').call(uiIssuesInfo(context));
91413 aboutList.append('li').attr('class', 'feature-warning').call(uiFeatureInfo(context));
91414 var issueLinks = aboutList.append('li');
91415 issueLinks.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/issues').call(svgIcon('#iD-icon-bug', 'light')).call(uiTooltip().title(_t.html('report_a_bug')).placement('top'));
91416 issueLinks.append('a').attr('target', '_blank').attr('href', 'https://github.com/openstreetmap/iD/blob/develop/CONTRIBUTING.md#translating').call(svgIcon('#iD-icon-translate', 'light')).call(uiTooltip().title(_t.html('help_translate')).placement('top'));
91417 aboutList.append('li').attr('class', 'version').call(uiVersion(context));
91419 if (!context.embed()) {
91420 aboutList.call(uiAccount(context));
91421 } // Setup map dimensions and move map to initial center/zoom.
91422 // This should happen after .main-content and toolbars exist.
91426 map.redrawEnable(true);
91427 ui.hash = behaviorHash(context);
91430 if (!ui.hash.hadHash) {
91431 map.centerZoom([0, 0], 2);
91435 window.onbeforeunload = function () {
91436 return context.save();
91439 window.onunload = function () {
91440 context.history().unlock();
91443 select(window).on('resize.editor', function () {
91446 var panPixels = 80;
91447 context.keybinding().on('⌫', function (d3_event) {
91448 d3_event.preventDefault();
91449 }).on([_t('sidebar.key'), '`', '²', '@'], ui.sidebar.toggle) // #5663, #6864 - common QWERTY, AZERTY
91450 .on('←', pan([panPixels, 0])).on('↑', pan([0, panPixels])).on('→', pan([-panPixels, 0])).on('↓', pan([0, -panPixels])).on(uiCmd('⌥←'), pan([map.dimensions()[0], 0])).on(uiCmd('⌥↑'), pan([0, map.dimensions()[1]])).on(uiCmd('⌥→'), pan([-map.dimensions()[0], 0])).on(uiCmd('⌥↓'), pan([0, -map.dimensions()[1]])).on(uiCmd('⌘' + _t('background.key')), function quickSwitch(d3_event) {
91452 d3_event.stopImmediatePropagation();
91453 d3_event.preventDefault();
91456 var previousBackground = context.background().findSource(corePreferences('background-last-used-toggle'));
91458 if (previousBackground) {
91459 var currentBackground = context.background().baseLayerSource();
91460 corePreferences('background-last-used-toggle', currentBackground.id);
91461 corePreferences('background-last-used', previousBackground.id);
91462 context.background().baseLayerSource(previousBackground);
91464 }).on(_t('area_fill.wireframe.key'), function toggleWireframe(d3_event) {
91465 d3_event.preventDefault();
91466 d3_event.stopPropagation();
91467 context.map().toggleWireframe();
91468 }).on(uiCmd('⌥' + _t('area_fill.wireframe.key')), function toggleOsmData(d3_event) {
91469 d3_event.preventDefault();
91470 d3_event.stopPropagation(); // Don't allow layer changes while drawing - #6584
91472 var mode = context.mode();
91473 if (mode && /^draw/.test(mode.id)) return;
91474 var layer = context.layers().layer('osm');
91477 layer.enabled(!layer.enabled());
91479 if (!layer.enabled()) {
91480 context.enter(modeBrowse(context));
91483 }).on(_t('map_data.highlight_edits.key'), function toggleHighlightEdited(d3_event) {
91484 d3_event.preventDefault();
91485 context.map().toggleHighlightEdited();
91487 context.on('enter.editor', function (entered) {
91488 container.classed('mode-' + entered.id, true);
91489 }).on('exit.editor', function (exited) {
91490 container.classed('mode-' + exited.id, false);
91492 context.enter(modeBrowse(context));
91494 if (!_initCounter++) {
91495 if (!ui.hash.startWalkthrough) {
91496 context.container().call(uiSplash(context)).call(uiRestore(context));
91499 context.container().call(ui.shortcuts);
91502 var osm = context.connection();
91503 var auth = uiLoading(context).message(_t.html('loading_auth')).blocking(true);
91506 osm.on('authLoading.ui', function () {
91507 context.container().call(auth);
91508 }).on('authDone.ui', function () {
91515 if (ui.hash.startWalkthrough) {
91516 ui.hash.startWalkthrough = false;
91517 context.container().call(uiIntro(context));
91521 return function (d3_event) {
91522 if (d3_event.shiftKey) return;
91523 if (context.container().select('.combobox').size()) return;
91524 d3_event.preventDefault();
91525 context.map().pan(d, 100);
91532 var _loadPromise; // renders the iD interface into the container node
91535 ui.ensureLoaded = function () {
91536 if (_loadPromise) return _loadPromise;
91537 return _loadPromise = Promise.all([// must have strings and presets before loading the UI
91538 _mainLocalizer.ensureLoaded(), _mainPresetIndex.ensureLoaded()]).then(function () {
91539 if (!context.container().empty()) render(context.container());
91540 })["catch"](function (err) {
91541 return console.error(err);
91542 }); // eslint-disable-line
91543 }; // `ui.restart()` will destroy and rebuild the entire iD interface,
91544 // for example to switch the locale while iD is running.
91547 ui.restart = function () {
91548 context.keybinding().clear();
91549 _loadPromise = null;
91550 context.container().selectAll('*').remove();
91554 ui.lastPointerType = function () {
91555 return _lastPointerType;
91558 ui.svgDefs = svgDefs(context);
91559 ui.flash = uiFlash(context);
91560 ui.sidebar = uiSidebar(context);
91561 ui.photoviewer = uiPhotoviewer(context);
91562 ui.shortcuts = uiShortcuts(context);
91564 ui.onResize = function (withPan) {
91565 var map = context.map(); // Recalc dimensions of map and sidebar.. (`true` = force recalc)
91566 // This will call `getBoundingClientRect` and trigger reflow,
91567 // but the values will be cached for later use.
91569 var mapDimensions = utilGetDimensions(context.container().select('.main-content'), true);
91570 utilGetDimensions(context.container().select('.sidebar'), true);
91572 if (withPan !== undefined) {
91573 map.redrawEnable(false);
91575 map.redrawEnable(true);
91578 map.dimensions(mapDimensions);
91579 ui.photoviewer.onMapResize(); // check if header or footer have overflowed
91581 ui.checkOverflow('.top-toolbar');
91582 ui.checkOverflow('.map-footer-bar'); // Use outdated code so it works on Explorer
91584 var resizeWindowEvent = document.createEvent('Event');
91585 resizeWindowEvent.initEvent('resizeWindow', true, true);
91586 document.dispatchEvent(resizeWindowEvent);
91587 }; // Call checkOverflow when resizing or whenever the contents change.
91590 ui.checkOverflow = function (selector, reset) {
91592 delete _needWidth[selector];
91595 var selection = context.container().select(selector);
91596 if (selection.empty()) return;
91597 var scrollWidth = selection.property('scrollWidth');
91598 var clientWidth = selection.property('clientWidth');
91599 var needed = _needWidth[selector] || scrollWidth;
91601 if (scrollWidth > clientWidth) {
91602 // overflow happening
91603 selection.classed('narrow', true);
91605 if (!_needWidth[selector]) {
91606 _needWidth[selector] = scrollWidth;
91608 } else if (scrollWidth >= needed) {
91609 selection.classed('narrow', false);
91613 ui.togglePanes = function (showPane) {
91614 var hidePanes = context.container().selectAll('.map-pane.shown');
91615 var side = _mainLocalizer.textDirection() === 'ltr' ? 'right' : 'left';
91616 hidePanes.classed('shown', false).classed('hide', true);
91617 context.container().selectAll('.map-pane-control button').classed('active', false);
91620 hidePanes.classed('shown', false).classed('hide', true).style(side, '-500px');
91621 context.container().selectAll('.' + showPane.attr('pane') + '-control button').classed('active', true);
91622 showPane.classed('shown', true).classed('hide', false);
91624 if (hidePanes.empty()) {
91625 showPane.style(side, '-500px').transition().duration(200).style(side, '0px');
91627 showPane.style(side, '0px');
91630 hidePanes.classed('shown', true).classed('hide', false).style(side, '0px').transition().duration(200).style(side, '-500px').on('end', function () {
91631 select(this).classed('shown', false).classed('hide', true);
91636 var _editMenu = uiEditMenu(context);
91638 ui.editMenu = function () {
91642 ui.showEditMenu = function (anchorPoint, triggerType, operations) {
91643 // remove any displayed menu
91644 ui.closeEditMenu();
91645 if (!operations && context.mode().operations) operations = context.mode().operations();
91646 if (!operations || !operations.length) return; // disable menu if in wide selection, for example
91648 if (!context.map().editableDataEnabled()) return;
91649 var surfaceNode = context.surface().node();
91651 if (surfaceNode.focus) {
91652 // FF doesn't support it
91653 // focus the surface or else clicking off the menu may not trigger modeBrowse
91654 surfaceNode.focus();
91657 operations.forEach(function (operation) {
91658 if (operation.point) operation.point(anchorPoint);
91661 _editMenu.anchorLoc(anchorPoint).triggerType(triggerType).operations(operations); // render the menu
91664 context.map().supersurface.call(_editMenu);
91667 ui.closeEditMenu = function () {
91668 // remove any existing menu no matter how it was added
91669 context.map().supersurface.select('.edit-menu').remove();
91672 var _saveLoading = select(null);
91674 context.uploader().on('saveStarted.ui', function () {
91675 _saveLoading = uiLoading(context).message(_t.html('save.uploading')).blocking(true);
91676 context.container().call(_saveLoading); // block input during upload
91677 }).on('saveEnded.ui', function () {
91678 _saveLoading.close();
91680 _saveLoading = select(null);
91685 function coreContext() {
91688 var dispatch = dispatch$8('enter', 'exit', 'change');
91689 var context = utilRebind({}, dispatch, 'on');
91691 var _deferred = new Set();
91693 context.version = '2.20.2';
91694 context.privacyVersion = '20201202'; // iD will alter the hash so cache the parameters intended to setup the session
91696 context.initialHashParams = window.location.hash ? utilStringQs(window.location.hash) : {};
91697 context.isFirstSession = !corePreferences('sawSplash') && !corePreferences('sawPrivacyVersion');
91699 // An osmChangeset object. Not loaded until needed.
91701 context.changeset = null;
91702 var _defaultChangesetComment = context.initialHashParams.comment;
91703 var _defaultChangesetSource = context.initialHashParams.source;
91704 var _defaultChangesetHashtags = context.initialHashParams.hashtags;
91706 context.defaultChangesetComment = function (val) {
91707 if (!arguments.length) return _defaultChangesetComment;
91708 _defaultChangesetComment = val;
91712 context.defaultChangesetSource = function (val) {
91713 if (!arguments.length) return _defaultChangesetSource;
91714 _defaultChangesetSource = val;
91718 context.defaultChangesetHashtags = function (val) {
91719 if (!arguments.length) return _defaultChangesetHashtags;
91720 _defaultChangesetHashtags = val;
91723 /* Document title */
91725 /* (typically shown as the label for the browser window/tab) */
91726 // If true, iD will update the title based on what the user is doing
91729 var _setsDocumentTitle = true;
91731 context.setsDocumentTitle = function (val) {
91732 if (!arguments.length) return _setsDocumentTitle;
91733 _setsDocumentTitle = val;
91735 }; // The part of the title that is always the same
91738 var _documentTitleBase = document.title;
91740 context.documentTitleBase = function (val) {
91741 if (!arguments.length) return _documentTitleBase;
91742 _documentTitleBase = val;
91745 /* User interface and keybinding */
91750 context.ui = function () {
91754 context.lastPointerType = function () {
91755 return _ui.lastPointerType();
91758 var _keybinding = utilKeybinding('context');
91760 context.keybinding = function () {
91761 return _keybinding;
91764 select(document).call(_keybinding);
91765 /* Straight accessors. Avoid using these if you can. */
91766 // Instantiate the connection here because it doesn't require passing in
91767 // `context` and it's needed for pre-init calls like `preauth`
91769 var _connection = services.osm;
91777 context.connection = function () {
91778 return _connection;
91781 context.history = function () {
91785 context.validator = function () {
91789 context.uploader = function () {
91795 context.preauth = function (options) {
91797 _connection["switch"](options);
91802 /* connection options for source switcher (optional) */
91805 var _apiConnections;
91807 context.apiConnections = function (val) {
91808 if (!arguments.length) return _apiConnections;
91809 _apiConnections = val;
91811 }; // A string or array or locale codes to prefer over the browser's settings
91814 context.locale = function (locale) {
91815 if (!arguments.length) return _mainLocalizer.localeCode();
91816 _mainLocalizer.preferredLocaleCodes(locale);
91820 function afterLoad(cid, callback) {
91821 return function (err, result) {
91823 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
91824 if (err.status === 400 || err.status === 401 || err.status === 403) {
91826 _connection.logout();
91830 if (typeof callback === 'function') {
91835 } else if (_connection && _connection.getConnectionId() !== cid) {
91836 if (typeof callback === 'function') {
91838 message: 'Connection Switched',
91845 _history.merge(result.data, result.extent);
91847 if (typeof callback === 'function') {
91848 callback(err, result);
91856 context.loadTiles = function (projection, callback) {
91857 var handle = window.requestIdleCallback(function () {
91858 _deferred["delete"](handle);
91860 if (_connection && context.editableDataEnabled()) {
91861 var cid = _connection.getConnectionId();
91863 _connection.loadTiles(projection, afterLoad(cid, callback));
91867 _deferred.add(handle);
91870 context.loadTileAtLoc = function (loc, callback) {
91871 var handle = window.requestIdleCallback(function () {
91872 _deferred["delete"](handle);
91874 if (_connection && context.editableDataEnabled()) {
91875 var cid = _connection.getConnectionId();
91877 _connection.loadTileAtLoc(loc, afterLoad(cid, callback));
91881 _deferred.add(handle);
91882 }; // Download the full entity and its parent relations. The callback may be called multiple times.
91885 context.loadEntity = function (entityID, callback) {
91887 var cid = _connection.getConnectionId();
91889 _connection.loadEntity(entityID, afterLoad(cid, callback)); // We need to fetch the parent relations separately.
91892 _connection.loadEntityRelations(entityID, afterLoad(cid, callback));
91896 context.zoomToEntity = function (entityID, zoomTo) {
91897 // be sure to load the entity even if we're not going to zoom to it
91898 context.loadEntity(entityID, function (err, result) {
91901 if (zoomTo !== false) {
91902 var entity = result.data.find(function (e) {
91903 return e.id === entityID;
91907 _map.zoomTo(entity);
91912 _map.on('drawn.zoomToEntity', function () {
91913 if (!context.hasEntity(entityID)) return;
91915 _map.on('drawn.zoomToEntity', null);
91917 context.on('enter.zoomToEntity', null);
91918 context.enter(modeSelect(context, [entityID]));
91921 context.on('enter.zoomToEntity', function () {
91922 if (_mode.id !== 'browse') {
91923 _map.on('drawn.zoomToEntity', null);
91925 context.on('enter.zoomToEntity', null);
91930 var _minEditableZoom = 16;
91932 context.minEditableZoom = function (val) {
91933 if (!arguments.length) return _minEditableZoom;
91934 _minEditableZoom = val;
91937 _connection.tileZoom(val);
91941 }; // String length limits in Unicode characters, not JavaScript UTF-16 code units
91944 context.maxCharsForTagKey = function () {
91948 context.maxCharsForTagValue = function () {
91952 context.maxCharsForRelationRole = function () {
91956 function cleanOsmString(val, maxChars) {
91957 // be lenient with input
91958 if (val === undefined || val === null) {
91961 val = val.toString();
91962 } // remove whitespace
91965 val = val.trim(); // use the canonical form of the string
91967 if (val.normalize) val = val.normalize('NFC'); // trim to the number of allowed characters
91969 return utilUnicodeCharsTruncated(val, maxChars);
91972 context.cleanTagKey = function (val) {
91973 return cleanOsmString(val, context.maxCharsForTagKey());
91976 context.cleanTagValue = function (val) {
91977 return cleanOsmString(val, context.maxCharsForTagValue());
91980 context.cleanRelationRole = function (val) {
91981 return cleanOsmString(val, context.maxCharsForRelationRole());
91986 var _inIntro = false;
91988 context.inIntro = function (val) {
91989 if (!arguments.length) return _inIntro;
91992 }; // Immediately save the user's history to localstorage, if possible
91993 // This is called someteimes, but also on the `window.onbeforeunload` handler
91996 context.save = function () {
91997 // no history save, no message onbeforeunload
91998 if (_inIntro || context.container().select('.modal').size()) return;
92001 if (_mode && _mode.id === 'save') {
92002 canSave = false; // Attempt to prevent user from creating duplicate changes - see #5200
92004 if (services.osm && services.osm.isChangesetInflight()) {
92005 _history.clearSaved();
92010 canSave = context.selectedIDs().every(function (id) {
92011 var entity = context.hasEntity(id);
92012 return entity && !entity.isDegenerate();
92020 if (_history.hasChanges()) {
92021 return _t('save.unsaved_changes');
92023 }; // Debounce save, since it's a synchronous localStorage write,
92024 // and history changes can happen frequently (e.g. when dragging).
92027 context.debouncedSave = debounce(context.save, 350);
92029 function withDebouncedSave(fn) {
92030 return function () {
92031 var result = fn.apply(_history, arguments);
92032 context.debouncedSave();
92039 context.hasEntity = function (id) {
92040 return _history.graph().hasEntity(id);
92043 context.entity = function (id) {
92044 return _history.graph().entity(id);
92051 context.mode = function () {
92055 context.enter = function (newMode) {
92059 dispatch.call('exit', _this, _mode);
92066 dispatch.call('enter', _this, _mode);
92069 context.selectedIDs = function () {
92070 return _mode && _mode.selectedIDs && _mode.selectedIDs() || [];
92073 context.activeID = function () {
92074 return _mode && _mode.activeID && _mode.activeID();
92077 var _selectedNoteID;
92079 context.selectedNoteID = function (noteID) {
92080 if (!arguments.length) return _selectedNoteID;
92081 _selectedNoteID = noteID;
92083 }; // NOTE: Don't change the name of this until UI v3 is merged
92086 var _selectedErrorID;
92088 context.selectedErrorID = function (errorID) {
92089 if (!arguments.length) return _selectedErrorID;
92090 _selectedErrorID = errorID;
92096 context.install = function (behavior) {
92097 return context.surface().call(behavior);
92100 context.uninstall = function (behavior) {
92101 return context.surface().call(behavior.off);
92108 context.copyGraph = function () {
92114 context.copyIDs = function (val) {
92115 if (!arguments.length) return _copyIDs;
92117 _copyGraph = _history.graph();
92123 context.copyLonLat = function (val) {
92124 if (!arguments.length) return _copyLonLat;
92133 context.background = function () {
92134 return _background;
92141 context.features = function () {
92145 context.hasHiddenConnections = function (id) {
92146 var graph = _history.graph();
92148 var entity = graph.entity(id);
92149 return _features.hasHiddenConnections(entity, graph);
92156 context.photos = function () {
92164 context.map = function () {
92168 context.layers = function () {
92169 return _map.layers();
92172 context.surface = function () {
92173 return _map.surface;
92176 context.editableDataEnabled = function () {
92177 return _map.editableDataEnabled();
92180 context.surfaceRect = function () {
92181 return _map.surface.node().getBoundingClientRect();
92184 context.editable = function () {
92185 // don't allow editing during save
92186 var mode = context.mode();
92187 if (!mode || mode.id === 'save') return false;
92188 return _map.editableDataEnabled();
92193 var _debugFlags = {
92197 // label collision bounding boxes
92199 // imagery bounding polygons
92202 downloaded: false // downloaded data from osm
92206 context.debugFlags = function () {
92207 return _debugFlags;
92210 context.getDebug = function (flag) {
92211 return flag && _debugFlags[flag];
92214 context.setDebug = function (flag, val) {
92215 if (arguments.length === 1) val = true;
92216 _debugFlags[flag] = val;
92217 dispatch.call('change');
92223 var _container = select(null);
92225 context.container = function (val) {
92226 if (!arguments.length) return _container;
92229 _container.classed('ideditor', true);
92234 context.containerNode = function (val) {
92235 if (!arguments.length) return context.container().node();
92236 context.container(select(val));
92242 context.embed = function (val) {
92243 if (!arguments.length) return _embed;
92250 var _assetPath = '';
92252 context.assetPath = function (val) {
92253 if (!arguments.length) return _assetPath;
92255 _mainFileFetcher.assetPath(val);
92259 var _assetMap = {};
92261 context.assetMap = function (val) {
92262 if (!arguments.length) return _assetMap;
92264 _mainFileFetcher.assetMap(val);
92268 context.asset = function (val) {
92269 if (/^http(s)?:\/\//i.test(val)) return val;
92270 var filename = _assetPath + val;
92271 return _assetMap[filename] || filename;
92274 context.imagePath = function (val) {
92275 return context.asset("img/".concat(val));
92277 /* reset (aka flush) */
92280 context.reset = context.flush = function () {
92281 context.debouncedSave.cancel();
92282 Array.from(_deferred).forEach(function (handle) {
92283 window.cancelIdleCallback(handle);
92285 _deferred["delete"](handle);
92287 Object.values(services).forEach(function (service) {
92288 if (service && typeof service.reset === 'function') {
92289 service.reset(context);
92292 context.changeset = null;
92294 _validator.reset();
92300 _uploader.reset(); // don't leave stale state in the inspector
92303 context.container().select('.inspector-wrap *').remove();
92309 context.projection = geoRawMercator();
92310 context.curtainProjection = geoRawMercator();
92313 context.init = function () {
92314 instantiateInternal();
92315 initializeDependents();
92316 return context; // Load variables and properties. No property of `context` should be accessed
92317 // until this is complete since load statuses are indeterminate. The order
92318 // of instantiation shouldn't matter.
92320 function instantiateInternal() {
92321 _history = coreHistory(context);
92322 context.graph = _history.graph;
92323 context.pauseChangeDispatch = _history.pauseChangeDispatch;
92324 context.resumeChangeDispatch = _history.resumeChangeDispatch;
92325 context.perform = withDebouncedSave(_history.perform);
92326 context.replace = withDebouncedSave(_history.replace);
92327 context.pop = withDebouncedSave(_history.pop);
92328 context.overwrite = withDebouncedSave(_history.overwrite);
92329 context.undo = withDebouncedSave(_history.undo);
92330 context.redo = withDebouncedSave(_history.redo);
92331 _validator = coreValidator(context);
92332 _uploader = coreUploader(context);
92333 _background = rendererBackground(context);
92334 _features = rendererFeatures(context);
92335 _map = rendererMap(context);
92336 _photos = rendererPhotos(context);
92337 _ui = uiInit(context);
92338 } // Set up objects that might need to access properties of `context`. The order
92339 // might matter if dependents make calls to each other. Be wary of async calls.
92342 function initializeDependents() {
92343 if (context.initialHashParams.presets) {
92344 _mainPresetIndex.addablePresetIDs(new Set(context.initialHashParams.presets.split(',')));
92347 if (context.initialHashParams.locale) {
92348 _mainLocalizer.preferredLocaleCodes(context.initialHashParams.locale);
92349 } // kick off some async work
92352 _mainLocalizer.ensureLoaded();
92354 _background.ensureLoaded();
92356 _mainPresetIndex.ensureLoaded();
92357 Object.values(services).forEach(function (service) {
92358 if (service && typeof service.init === 'function') {
92369 if (services.maprules && context.initialHashParams.maprules) {
92370 d3_json(context.initialHashParams.maprules).then(function (mapcss) {
92371 services.maprules.init();
92372 mapcss.forEach(function (mapcssSelector) {
92373 return services.maprules.addRule(mapcssSelector);
92375 })["catch"](function () {
92378 } // if the container isn't available, e.g. when testing, don't load the UI
92381 if (!context.container().empty()) {
92382 _ui.ensureLoaded().then(function () {
92392 // NSI contains the most correct tagging for many commonly mapped features.
92393 // See https://github.com/osmlab/name-suggestion-index and https://nsi.guide
92396 var _nsiStatus = 'loading'; // 'loading', 'ok', 'failed'
92398 var _nsi = {}; // Sometimes we can upgrade a feature tagged like `building=yes` to a better tag.
92400 var buildingPreset = {
92401 'building/commercial': true,
92402 'building/government': true,
92403 'building/hotel': true,
92404 'building/retail': true,
92405 'building/office': true,
92406 'building/supermarket': true,
92407 'building/yes': true
92408 }; // Exceptions to the namelike regexes.
92409 // Usually a tag suffix contains a language code like `name:en`, `name:ru`
92410 // but we want to exclude things like `operator:type`, `name:etymology`, etc..
92412 var notNames = /:(colou?r|type|forward|backward|left|right|etymology|pronunciation|wikipedia)$/i; // Exceptions to the branchlike regexes
92414 var notBranches = /(coop|express|wireless|factory|outlet)/i; // PRIVATE FUNCTIONS
92415 // `setNsiSources()`
92416 // Adds the sources to iD's filemap so we can start downloading data.
92419 function setNsiSources() {
92420 var nsiVersion = packageJSON.devDependencies['name-suggestion-index'];
92421 var v = parseVersion(nsiVersion);
92422 var vMinor = "".concat(v.major, ".").concat(v.minor);
92424 'nsi_data': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/nsi.min.json"),
92425 'nsi_dissolved': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/dissolved.min.json"),
92426 'nsi_features': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/featureCollection.min.json"),
92427 'nsi_generics': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/genericWords.min.json"),
92428 'nsi_presets': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/presets/nsi-id-presets.min.json"),
92429 'nsi_replacements': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/replacements.min.json"),
92430 'nsi_trees': "https://cdn.jsdelivr.net/npm/name-suggestion-index@".concat(vMinor, "/dist/trees.min.json")
92432 var fileMap = _mainFileFetcher.fileMap();
92434 for (var k in sources) {
92435 if (!fileMap[k]) fileMap[k] = sources[k];
92437 } // `loadNsiPresets()`
92438 // Returns a Promise fulfilled when the presets have been downloaded and merged into iD.
92442 function loadNsiPresets() {
92443 return Promise.all([_mainFileFetcher.get('nsi_presets'), _mainFileFetcher.get('nsi_features')]).then(function (vals) {
92444 // Add `suggestion=true` to all the nsi presets
92445 // The preset json schema doesn't include it, but the iD code still uses it
92446 Object.values(vals[0].presets).forEach(function (preset) {
92447 return preset.suggestion = true;
92449 _mainPresetIndex.merge({
92450 presets: vals[0].presets,
92451 featureCollection: vals[1]
92454 } // `loadNsiData()`
92455 // Returns a Promise fulfilled when the other data have been downloaded and processed
92459 function loadNsiData() {
92460 return Promise.all([_mainFileFetcher.get('nsi_data'), _mainFileFetcher.get('nsi_dissolved'), _mainFileFetcher.get('nsi_replacements'), _mainFileFetcher.get('nsi_trees')]).then(function (vals) {
92463 // the raw name-suggestion-index data
92464 dissolved: vals[1].dissolved,
92465 // list of dissolved items
92466 replacements: vals[2].replacements,
92467 // trivial old->new qid replacements
92468 trees: vals[3].trees,
92469 // metadata about trees, main tags
92471 // Map (k -> Map (v -> t) )
92473 // Map (wd/wp tag values -> qids)
92474 ids: new Map() // Map (id -> NSI item)
92477 _nsi.matcher = new Matcher();
92479 _nsi.matcher.buildMatchIndex(_nsi.data);
92481 _nsi.matcher.buildLocationIndex(_nsi.data, _mainLocations.loco());
92483 Object.keys(_nsi.data).forEach(function (tkv) {
92484 var category = _nsi.data[tkv];
92485 var parts = tkv.split('/', 3); // tkv = "tree/key/value"
92489 var v = parts[2]; // Build a reverse index of keys -> values -> trees present in the name-suggestion-index
92490 // Collect primary keys (e.g. "amenity", "craft", "shop", "man_made", "route", etc)
92492 // "restaurant": "brands"
92495 var vmap = _nsi.kvt.get(k);
92500 _nsi.kvt.set(k, vmap);
92504 var tree = _nsi.trees[t]; // e.g. "brands", "operators"
92506 var mainTag = tree.mainTag; // e.g. "brand:wikidata", "operator:wikidata", etc
92508 var items = category.items || [];
92509 items.forEach(function (item) {
92510 // Remember some useful things for later, cache NSI id -> item
92512 item.mainTag = mainTag;
92514 _nsi.ids.set(item.id, item); // Cache Wikidata/Wikipedia values -> qid, for #6416
92517 var wd = item.tags[mainTag];
92518 var wp = item.tags[mainTag.replace('wikidata', 'wikipedia')];
92519 if (wd) _nsi.qids.set(wd, wd);
92520 if (wp && wd) _nsi.qids.set(wp, wd);
92525 // Gather all the k/v pairs that we will run through the NSI matcher.
92526 // An OSM tags object can contain anything, but only a few tags will be interesting to NSI.
92528 // This function will return the interesting tag pairs like:
92529 // "amenity/restaurant", "man_made/flagpole"
92530 // and fallbacks like
92532 // excluding things like
92533 // "tiger:reviewed", "surface", "ref", etc.
92536 // `tags`: `Object` containing the feature's OSM tags
92538 // `Object` containing kv pairs to test:
92540 // 'primary': Set(),
92541 // 'alternate': Set()
92546 function gatherKVs(tags) {
92547 var primary = new Set();
92548 var alternate = new Set();
92549 Object.keys(tags).forEach(function (osmkey) {
92550 var osmvalue = tags[osmkey];
92551 if (!osmvalue) return; // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92553 if (osmkey === 'route_master') osmkey = 'route';
92555 var vmap = _nsi.kvt.get(osmkey);
92557 if (!vmap) return; // not an interesting key
92559 if (vmap.get(osmvalue)) {
92560 // Matched a category in NSI
92561 primary.add("".concat(osmkey, "/").concat(osmvalue)); // interesting key/value
92562 } else if (osmvalue === 'yes') {
92563 alternate.add("".concat(osmkey, "/").concat(osmvalue)); // fallback key/yes
92565 }); // Can we try a generic building fallback match? - See #6122, #7197
92566 // Only try this if we do a preset match and find nothing else remarkable about that building.
92567 // For example, a way with `building=yes` + `name=Westfield` may be a Westfield department store.
92568 // But a way with `building=yes` + `name=Westfield` + `public_transport=station` is a train station for a town named "Westfield"
92570 var preset = _mainPresetIndex.matchTags(tags, 'area');
92572 if (buildingPreset[preset.id]) {
92573 alternate.add('building/yes');
92578 alternate: alternate
92580 } // `identifyTree()`
92581 // NSI has a concept of trees: "brands", "operators", "flags", "transit".
92582 // The tree determines things like which tags are namelike, and which tags hold important wikidata.
92583 // This takes an Object of tags and tries to identify what tree to use.
92586 // `tags`: `Object` containing the feature's OSM tags
92588 // `string` the name of the tree if known
92589 // or 'unknown' if it could match several trees (e.g. amenity/yes)
92590 // or null if no match
92594 function identifyTree(tags) {
92596 var t; // Check all tags
92598 Object.keys(tags).forEach(function (osmkey) {
92599 if (t) return; // found already
92601 var osmvalue = tags[osmkey];
92602 if (!osmvalue) return; // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92604 if (osmkey === 'route_master') osmkey = 'route';
92606 var vmap = _nsi.kvt.get(osmkey);
92608 if (!vmap) return; // this key is not in nsi
92610 if (osmvalue === 'yes') {
92611 unknown = 'unknown';
92613 t = vmap.get(osmvalue);
92616 return t || unknown || null;
92617 } // `gatherNames()`
92618 // Gather all the namelike values that we will run through the NSI matcher.
92619 // It will gather values primarily from tags `name`, `name:ru`, `flag:name`
92620 // and fallback to alternate tags like `brand`, `brand:ru`, `alt_name`
92623 // `tags`: `Object` containing the feature's OSM tags
92625 // `Object` containing namelike values to test:
92627 // 'primary': Set(),
92628 // 'fallbacks': Set()
92633 function gatherNames(tags) {
92635 primary: new Set(),
92636 alternate: new Set()
92638 var primary = new Set();
92639 var alternate = new Set();
92640 var foundSemi = false;
92641 var testNameFragments = false;
92642 var patterns; // Patterns for matching OSM keys that might contain namelike values.
92643 // These roughly correspond to the "trees" concept in name-suggestion-index,
92645 var t = identifyTree(tags);
92646 if (!t) return empty;
92648 if (t === 'transit') {
92650 primary: /^network$/i,
92651 alternate: /^(operator|operator:\w+|network:\w+|\w+_name|\w+_name:\w+)$/i
92653 } else if (t === 'flags') {
92655 primary: /^(flag:name|flag:name:\w+)$/i,
92656 alternate: /^(flag|flag:\w+|subject|subject:\w+)$/i // note: no `country`, we special-case it below
92659 } else if (t === 'brands') {
92660 testNameFragments = true;
92662 primary: /^(name|name:\w+)$/i,
92663 alternate: /^(brand|brand:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
92665 } else if (t === 'operators') {
92666 testNameFragments = true;
92668 primary: /^(name|name:\w+|operator|operator:\w+)$/i,
92669 alternate: /^(brand|brand:\w+|\w+_name|\w+_name:\w+)/i
92672 // unknown/multiple
92673 testNameFragments = true;
92675 primary: /^(name|name:\w+)$/i,
92676 alternate: /^(brand|brand:\w+|network|network:\w+|operator|operator:\w+|\w+_name|\w+_name:\w+)/i
92678 } // Test `name` fragments, longest to shortest, to fit them into a "Name Branch" pattern.
92679 // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
92682 if (tags.name && testNameFragments) {
92683 var nameParts = tags.name.split(/[\s\-\/,.]/);
92685 for (var split = nameParts.length; split > 0; split--) {
92686 var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
92690 } // Check all tags
92693 Object.keys(tags).forEach(function (osmkey) {
92694 var osmvalue = tags[osmkey];
92695 if (!osmvalue) return;
92697 if (isNamelike(osmkey, 'primary')) {
92698 if (/;/.test(osmvalue)) {
92701 primary.add(osmvalue);
92702 alternate["delete"](osmvalue);
92704 } else if (!primary.has(osmvalue) && isNamelike(osmkey, 'alternate')) {
92705 if (/;/.test(osmvalue)) {
92708 alternate.add(osmvalue);
92711 }); // For flags only, fallback to `country` tag only if no other namelike values were found.
92712 // See https://github.com/openstreetmap/iD/pull/8305#issuecomment-769174070
92714 if (tags.man_made === 'flagpole' && !primary.size && !alternate.size && !!tags.country) {
92715 var osmvalue = tags.country;
92717 if (/;/.test(osmvalue)) {
92720 alternate.add(osmvalue);
92722 } // If any namelike value contained a semicolon, return empty set and don't try matching anything.
92730 alternate: alternate
92734 function isNamelike(osmkey, which) {
92735 if (osmkey === 'old_name') return false;
92736 return patterns[which].test(osmkey) && !notNames.test(osmkey);
92738 } // `gatherTuples()`
92739 // Generate all combinations of [key,value,name] that we want to test.
92740 // This prioritizes them so that the primary name and k/v pairs go first
92743 // `tryKVs`: `Object` containing primary and alternate k/v pairs to test
92744 // `tryNames`: `Object` containing primary and alternate names to test
92746 // `Array`: tuple objects ordered by priority
92750 function gatherTuples(tryKVs, tryNames) {
92752 ['primary', 'alternate'].forEach(function (whichName) {
92753 // test names longest to shortest
92754 var arr = Array.from(tryNames[whichName]).sort(function (a, b) {
92755 return b.length - a.length;
92757 arr.forEach(function (n) {
92758 ['primary', 'alternate'].forEach(function (whichKV) {
92759 tryKVs[whichKV].forEach(function (kv) {
92760 var parts = kv.split('/', 2);
92773 } // `_upgradeTags()`
92774 // Try to match a feature to a canonical record in name-suggestion-index
92775 // and upgrade the tags to match.
92778 // `tags`: `Object` containing the feature's OSM tags
92779 // `loc`: Location where this feature exists, as a [lon, lat]
92781 // `Object` containing the result, or `null` if no changes needed:
92783 // 'newTags': `Object` - The tags the the feature should have
92784 // 'matched': `Object` - The matched item
92789 function _upgradeTags(tags, loc) {
92790 var newTags = Object.assign({}, tags); // shallow copy
92792 var changed = false; // Before anything, perform trivial Wikipedia/Wikidata replacements
92794 Object.keys(newTags).forEach(function (osmkey) {
92795 var matchTag = osmkey.match(/^(\w+:)?wikidata$/);
92798 // Look at '*:wikidata' tags
92799 var prefix = matchTag[1] || '';
92800 var wd = newTags[osmkey];
92801 var replace = _nsi.replacements[wd]; // If it matches a QID in the replacement list...
92803 if (replace && replace.wikidata !== undefined) {
92804 // replace or delete `*:wikidata` tag
92807 if (replace.wikidata) {
92808 newTags[osmkey] = replace.wikidata;
92810 delete newTags[osmkey];
92814 if (replace && replace.wikipedia !== undefined) {
92815 // replace or delete `*:wikipedia` tag
92817 var wpkey = "".concat(prefix, "wikipedia");
92819 if (replace.wikipedia) {
92820 newTags[wpkey] = replace.wikipedia;
92822 delete newTags[wpkey];
92826 }); // Match a 'route_master' as if it were a 'route' - name-suggestion-index#5184
92828 var isRouteMaster = tags.type === 'route_master'; // Gather key/value tag pairs to try to match
92830 var tryKVs = gatherKVs(tags);
92832 if (!tryKVs.primary.size && !tryKVs.alternate.size) {
92837 } // Gather namelike tag values to try to match
92840 var tryNames = gatherNames(tags); // Do `wikidata=*` or `wikipedia=*` tags identify this entity as a chain? - See #6416
92841 // If so, these tags can be swapped to e.g. `brand:wikidata`/`brand:wikipedia`.
92843 var foundQID = _nsi.qids.get(tags.wikidata) || _nsi.qids.get(tags.wikipedia);
92845 if (foundQID) tryNames.primary.add(foundQID); // matcher will recognize the Wikidata QID as name too
92847 if (!tryNames.primary.size && !tryNames.alternate.size) {
92852 } // Order the [key,value,name] tuples - test primary before alternate
92855 var tuples = gatherTuples(tryKVs, tryNames);
92857 var _loop = function _loop(i) {
92858 var tuple = tuples[i];
92860 var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n, loc); // Attempt to match an item in NSI
92863 if (!hits || !hits.length) return "continue"; // no match, try next tuple
92865 if (hits[0].match !== 'primary' && hits[0].match !== 'alternate') return "break"; // a generic match, stop looking
92866 // A match may contain multiple results, the first one is likely the best one for this location
92867 // e.g. `['pfk-a54c14', 'kfc-1ff19c', 'kfc-658eea']`
92869 var itemID = void 0,
92872 for (var j = 0; j < hits.length; j++) {
92874 itemID = hit.itemID;
92875 if (_nsi.dissolved[itemID]) continue; // Don't upgrade to a dissolved item
92877 item = _nsi.ids.get(itemID);
92878 if (!item) continue;
92879 var mainTag = item.mainTag; // e.g. `brand:wikidata`
92881 var itemQID = item.tags[mainTag]; // e.g. `brand:wikidata` qid
92883 var notQID = newTags["not:".concat(mainTag)]; // e.g. `not:brand:wikidata` qid
92885 if ( // Exceptions, skip this hit
92886 !itemQID || itemQID === notQID || // No `*:wikidata` or matched a `not:*:wikidata`
92887 newTags.office && !item.tags.office // feature may be a corporate office for a brand? - #6416
92890 continue; // continue looking
92892 break; // use `item`
92894 } // Can't use any of these hits, try next tuple..
92897 if (!item) return "continue"; // At this point we have matched a canonical item and can suggest tag upgrades..
92899 item = JSON.parse(JSON.stringify(item)); // deep copy
92901 var tkv = item.tkv;
92902 var parts = tkv.split('/', 3); // tkv = "tree/key/value"
92906 var category = _nsi.data[tkv];
92907 var properties = category.properties || {}; // Preserve some tags that we specifically don't want NSI to overwrite. ('^name', sometimes)
92909 var preserveTags = item.preserveTags || properties.preserveTags || []; // These tags can be toplevel tags -or- attributes - so we generally want to preserve existing values - #8615
92910 // We'll only _replace_ the tag value if this tag is the toplevel/defining tag for the matched item (`k`)
92912 ['building', 'emergency', 'internet_access', 'takeaway'].forEach(function (osmkey) {
92913 if (k !== osmkey) preserveTags.push("^".concat(osmkey, "$"));
92915 var regexes = preserveTags.map(function (s) {
92916 return new RegExp(s, 'i');
92919 Object.keys(newTags).forEach(function (osmkey) {
92920 if (regexes.some(function (regex) {
92921 return regex.test(osmkey);
92923 keepTags[osmkey] = newTags[osmkey];
92925 }); // Remove any primary tags ("amenity", "craft", "shop", "man_made", "route", etc) that have a
92926 // value like `amenity=yes` or `shop=yes` (exceptions have already been added to `keepTags` above)
92928 _nsi.kvt.forEach(function (vmap, k) {
92929 if (newTags[k] === 'yes') delete newTags[k];
92930 }); // Replace mistagged `wikidata`/`wikipedia` with e.g. `brand:wikidata`/`brand:wikipedia`
92934 delete newTags.wikipedia;
92935 delete newTags.wikidata;
92936 } // Do the tag upgrade
92939 Object.assign(newTags, item.tags, keepTags); // Swap `route` back to `route_master` - name-suggestion-index#5184
92941 if (isRouteMaster) {
92942 newTags.route_master = newTags.route;
92943 delete newTags.route;
92944 } // Special `branch` splitting rules - IF..
92945 // - NSI is suggesting to replace `name`, AND
92946 // - `branch` doesn't already contain something, AND
92947 // - original name has not moved to an alternate name (e.g. "Dunkin' Donuts" -> "Dunkin'"), AND
92948 // - original name is "some name" + "some stuff", THEN
92949 // consider splitting `name` into `name`/`branch`..
92952 var origName = tags.name;
92953 var newName = newTags.name;
92955 if (newName && origName && newName !== origName && !newTags.branch) {
92956 var newNames = gatherNames(newTags);
92957 var newSet = new Set([].concat(_toConsumableArray(newNames.primary), _toConsumableArray(newNames.alternate)));
92958 var isMoved = newSet.has(origName); // another tag holds the original name now
92961 // Test name fragments, longest to shortest, to fit them into a "Name Branch" pattern.
92962 // e.g. "TUI ReiseCenter - Neuss Innenstadt" -> ["TUI", "ReiseCenter", "Neuss", "Innenstadt"]
92963 var nameParts = origName.split(/[\s\-\/,.]/);
92965 for (var split = nameParts.length; split > 0; split--) {
92966 var name = nameParts.slice(0, split).join(' '); // e.g. "TUI ReiseCenter"
92968 var branch = nameParts.slice(split).join(' '); // e.g. "Neuss Innenstadt"
92970 var nameHits = _nsi.matcher.match(k, v, name, loc);
92972 if (!nameHits || !nameHits.length) continue; // no match, try next name fragment
92974 if (nameHits.some(function (hit) {
92975 return hit.itemID === itemID;
92977 // matched the name fragment to the same itemID above
92979 if (notBranches.test(branch)) {
92980 // "branch" was detected but is noise ("factory outlet", etc)
92981 newTags.name = origName; // Leave `name` alone, this part of the name may be significant..
92983 var branchHits = _nsi.matcher.match(k, v, branch, loc);
92985 if (branchHits && branchHits.length) {
92986 // if "branch" matched something else in NSI..
92987 if (branchHits[0].match === 'primary' || branchHits[0].match === 'alternate') {
92988 // if another brand! (e.g. "KFC - Taco Bell"?)
92991 }; // bail out - can't suggest tags in this case
92992 } // else a generic (e.g. "gas", "cafe") - ignore
92995 // "branch" is not noise and not something in NSI
92996 newTags.branch = branch; // Stick it in the `branch` tag..
93015 for (var i = 0; i < tuples.length; i++) {
93016 var _ret = _loop(i);
93018 if (_ret === "continue") continue;
93019 if (_ret === "break") break;
93020 if (_typeof(_ret) === "object") return _ret.v;
93027 } // `_isGenericName()`
93028 // Is the `name` tag generic?
93031 // `tags`: `Object` containing the feature's OSM tags
93033 // `true` if it is generic, `false` if not
93037 function _isGenericName(tags) {
93039 if (!n) return false; // tryNames just contains the `name` tag value and nothing else
93042 primary: new Set([n]),
93043 alternate: new Set()
93044 }; // Gather key/value tag pairs to try to match
93046 var tryKVs = gatherKVs(tags);
93047 if (!tryKVs.primary.size && !tryKVs.alternate.size) return false; // Order the [key,value,name] tuples - test primary before alternate
93049 var tuples = gatherTuples(tryKVs, tryNames);
93051 for (var i = 0; i < tuples.length; i++) {
93052 var tuple = tuples[i];
93054 var hits = _nsi.matcher.match(tuple.k, tuple.v, tuple.n); // Attempt to match an item in NSI
93055 // If we get a `excludeGeneric` hit, this is a generic name.
93058 if (hits && hits.length && hits[0].match === 'excludeGeneric') return true;
93062 } // PUBLIC INTERFACE
93067 // On init, start preparing the name-suggestion-index
93069 init: function init() {
93070 // Note: service.init is called immediately after the presetManager has started loading its data.
93071 // We expect to chain onto an unfulfilled promise here.
93073 _mainPresetIndex.ensureLoaded().then(function () {
93074 return loadNsiPresets();
93075 }).then(function () {
93077 }) // wait briefly for locationSets to enter the locationManager queue
93078 .then(function () {
93079 return _mainLocations.mergeLocationSets([]);
93080 }) // wait for locationSets to resolve
93081 .then(function () {
93082 return loadNsiData();
93083 }).then(function () {
93084 return _nsiStatus = 'ok';
93085 })["catch"](function () {
93086 return _nsiStatus = 'failed';
93089 function delay(msec) {
93090 return new Promise(function (resolve) {
93091 window.setTimeout(resolve, msec);
93096 // Reset is called when user saves data to OSM (does nothing here)
93098 reset: function reset() {},
93100 // To let other code know how it's going...
93103 // `String`: 'loading', 'ok', 'failed'
93105 status: function status() {
93108 // `isGenericName()`
93109 // Is the `name` tag generic?
93112 // `tags`: `Object` containing the feature's OSM tags
93114 // `true` if it is generic, `false` if not
93116 isGenericName: function isGenericName(tags) {
93117 return _isGenericName(tags);
93120 // Suggest tag upgrades.
93121 // This function will not modify the input tags, it makes a copy.
93124 // `tags`: `Object` containing the feature's OSM tags
93125 // `loc`: Location where this feature exists, as a [lon, lat]
93127 // `Object` containing the result, or `null` if no changes needed:
93129 // 'newTags': `Object` - The tags the the feature should have
93130 // 'matched': `Object` - The matched item
93133 upgradeTags: function upgradeTags(tags, loc) {
93134 return _upgradeTags(tags, loc);
93137 // Direct access to the NSI cache, useful for testing or breaking things
93140 // `Object`: the internal NSI cache
93142 cache: function cache() {
93147 var apibase$1 = 'https://openstreetcam.org';
93148 var maxResults$1 = 1000;
93149 var tileZoom$1 = 14;
93150 var tiler$3 = utilTiler().zoomExtent([tileZoom$1, tileZoom$1]).skipNullIsland(true);
93151 var dispatch$3 = dispatch$8('loadedImages');
93152 var imgZoom = d3_zoom().extent([[0, 0], [320, 240]]).translateExtent([[0, 0], [320, 240]]).scaleExtent([1, 15]);
93156 var _oscSelectedImage;
93158 var _loadViewerPromise$1;
93160 function abortRequest$3(controller) {
93161 controller.abort();
93164 function maxPageAtZoom(z) {
93165 if (z < 15) return 2;
93166 if (z === 15) return 5;
93167 if (z === 16) return 10;
93168 if (z === 17) return 20;
93169 if (z === 18) return 40;
93170 if (z > 18) return 80;
93173 function loadTiles$1(which, url, projection) {
93174 var currZoom = Math.floor(geoScaleToZoom(projection.scale()));
93175 var tiles = tiler$3.getTiles(projection); // abort inflight requests that are no longer needed
93177 var cache = _oscCache[which];
93178 Object.keys(cache.inflight).forEach(function (k) {
93179 var wanted = tiles.find(function (tile) {
93180 return k.indexOf(tile.id + ',') === 0;
93184 abortRequest$3(cache.inflight[k]);
93185 delete cache.inflight[k];
93188 tiles.forEach(function (tile) {
93189 loadNextTilePage$1(which, currZoom, url, tile);
93193 function loadNextTilePage$1(which, currZoom, url, tile) {
93194 var cache = _oscCache[which];
93195 var bbox = tile.extent.bbox();
93196 var maxPages = maxPageAtZoom(currZoom);
93197 var nextPage = cache.nextPage[tile.id] || 1;
93198 var params = utilQsString({
93201 // client_id: clientId,
93202 bbTopLeft: [bbox.maxY, bbox.minX].join(','),
93203 bbBottomRight: [bbox.minY, bbox.maxX].join(',')
93205 if (nextPage > maxPages) return;
93206 var id = tile.id + ',' + String(nextPage);
93207 if (cache.loaded[id] || cache.inflight[id]) return;
93208 var controller = new AbortController();
93209 cache.inflight[id] = controller;
93212 signal: controller.signal,
93215 'Content-Type': 'application/x-www-form-urlencoded'
93218 d3_json(url, options).then(function (data) {
93219 cache.loaded[id] = true;
93220 delete cache.inflight[id];
93222 if (!data || !data.currentPageItems || !data.currentPageItems.length) {
93223 throw new Error('No Data');
93226 var features = data.currentPageItems.map(function (item) {
93227 var loc = [+item.lng, +item.lat];
93230 if (which === 'images') {
93235 captured_at: item.shot_date || item.date_added,
93236 captured_by: item.username,
93237 imagePath: item.lth_name,
93238 sequence_id: item.sequence_id,
93239 sequence_index: +item.sequence_index
93240 }; // cache sequence info
93242 var seq = _oscCache.sequences[d.sequence_id];
93249 _oscCache.sequences[d.sequence_id] = seq;
93252 seq.images[d.sequence_index] = d;
93253 _oscCache.images.forImageKey[d.key] = d; // cache imageKey -> image
93264 cache.rtree.load(features);
93266 if (data.currentPageItems.length === maxResults$1) {
93267 // more pages to load
93268 cache.nextPage[tile.id] = nextPage + 1;
93269 loadNextTilePage$1(which, currZoom, url, tile);
93271 cache.nextPage[tile.id] = Infinity; // no more pages to load
93274 if (which === 'images') {
93275 dispatch$3.call('loadedImages');
93277 })["catch"](function () {
93278 cache.loaded[id] = true;
93279 delete cache.inflight[id];
93281 } // partition viewport into higher zoom tiles
93284 function partitionViewport$1(projection) {
93285 var z = geoScaleToZoom(projection.scale());
93286 var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
93288 var tiler = utilTiler().zoomExtent([z2, z2]);
93289 return tiler.getTiles(projection).map(function (tile) {
93290 return tile.extent;
93292 } // no more than `limit` results per partition.
93295 function searchLimited$1(limit, projection, rtree) {
93296 limit = limit || 5;
93297 return partitionViewport$1(projection).reduce(function (result, extent) {
93298 var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
93301 return found.length ? result.concat(found) : result;
93305 var serviceOpenstreetcam = {
93306 init: function init() {
93311 this.event = utilRebind(this, dispatch$3, 'on');
93313 reset: function reset() {
93315 Object.values(_oscCache.images.inflight).forEach(abortRequest$3);
93323 rtree: new RBush(),
93328 _oscSelectedImage = null;
93330 images: function images(projection) {
93332 return searchLimited$1(limit, projection, _oscCache.images.rtree);
93334 sequences: function sequences(projection) {
93335 var viewport = projection.clipExtent();
93336 var min = [viewport[0][0], viewport[1][1]];
93337 var max = [viewport[1][0], viewport[0][1]];
93338 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
93339 var sequenceKeys = {}; // all sequences for images in viewport
93341 _oscCache.images.rtree.search(bbox).forEach(function (d) {
93342 sequenceKeys[d.data.sequence_id] = true;
93343 }); // make linestrings from those sequences
93346 var lineStrings = [];
93347 Object.keys(sequenceKeys).forEach(function (sequenceKey) {
93348 var seq = _oscCache.sequences[sequenceKey];
93349 var images = seq && seq.images;
93353 type: 'LineString',
93354 coordinates: images.map(function (d) {
93356 }).filter(Boolean),
93358 captured_at: images[0] ? images[0].captured_at : null,
93359 captured_by: images[0] ? images[0].captured_by : null,
93365 return lineStrings;
93367 cachedImage: function cachedImage(imageKey) {
93368 return _oscCache.images.forImageKey[imageKey];
93370 loadImages: function loadImages(projection) {
93371 var url = apibase$1 + '/1.0/list/nearby-photos/';
93372 loadTiles$1('images', url, projection);
93374 ensureViewerLoaded: function ensureViewerLoaded(context) {
93375 if (_loadViewerPromise$1) return _loadViewerPromise$1; // add osc-wrapper
93377 var wrap = context.container().select('.photoviewer').selectAll('.osc-wrapper').data([0]);
93379 var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper osc-wrapper').classed('hide', true).call(imgZoom.on('zoom', zoomPan)).on('dblclick.zoom', null);
93380 wrapEnter.append('div').attr('class', 'photo-attribution fillD');
93381 var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
93382 controlsEnter.append('button').on('click.back', step(-1)).html('◄');
93383 controlsEnter.append('button').on('click.rotate-ccw', rotate(-90)).html('⤿');
93384 controlsEnter.append('button').on('click.rotate-cw', rotate(90)).html('⤾');
93385 controlsEnter.append('button').on('click.forward', step(1)).html('►');
93386 wrapEnter.append('div').attr('class', 'osc-image-wrap'); // Register viewer resize handler
93388 context.ui().photoviewer.on('resize.openstreetcam', function (dimensions) {
93389 imgZoom = d3_zoom().extent([[0, 0], dimensions]).translateExtent([[0, 0], dimensions]).scaleExtent([1, 15]).on('zoom', zoomPan);
93392 function zoomPan(d3_event) {
93393 var t = d3_event.transform;
93394 context.container().select('.photoviewer .osc-image-wrap').call(utilSetTransform, t.x, t.y, t.k);
93397 function rotate(deg) {
93398 return function () {
93399 if (!_oscSelectedImage) return;
93400 var sequenceKey = _oscSelectedImage.sequence_id;
93401 var sequence = _oscCache.sequences[sequenceKey];
93402 if (!sequence) return;
93403 var r = sequence.rotation || 0;
93405 if (r > 180) r -= 360;
93406 if (r < -180) r += 360;
93407 sequence.rotation = r;
93408 var wrap = context.container().select('.photoviewer .osc-wrapper');
93409 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
93410 wrap.selectAll('.osc-image').transition().duration(100).style('transform', 'rotate(' + r + 'deg)');
93414 function step(stepBy) {
93415 return function () {
93416 if (!_oscSelectedImage) return;
93417 var sequenceKey = _oscSelectedImage.sequence_id;
93418 var sequence = _oscCache.sequences[sequenceKey];
93419 if (!sequence) return;
93420 var nextIndex = _oscSelectedImage.sequence_index + stepBy;
93421 var nextImage = sequence.images[nextIndex];
93422 if (!nextImage) return;
93423 context.map().centerEase(nextImage.loc);
93424 that.selectImage(context, nextImage.key);
93426 } // don't need any async loading so resolve immediately
93429 _loadViewerPromise$1 = Promise.resolve();
93430 return _loadViewerPromise$1;
93432 showViewer: function showViewer(context) {
93433 var viewer = context.container().select('.photoviewer').classed('hide', false);
93434 var isHidden = viewer.selectAll('.photo-wrapper.osc-wrapper.hide').size();
93437 viewer.selectAll('.photo-wrapper:not(.osc-wrapper)').classed('hide', true);
93438 viewer.selectAll('.photo-wrapper.osc-wrapper').classed('hide', false);
93443 hideViewer: function hideViewer(context) {
93444 _oscSelectedImage = null;
93445 this.updateUrlImage(null);
93446 var viewer = context.container().select('.photoviewer');
93447 if (!viewer.empty()) viewer.datum(null);
93448 viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
93449 context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
93450 return this.setStyles(context, null, true);
93452 selectImage: function selectImage(context, imageKey) {
93453 var d = this.cachedImage(imageKey);
93454 _oscSelectedImage = d;
93455 this.updateUrlImage(imageKey);
93456 var viewer = context.container().select('.photoviewer');
93457 if (!viewer.empty()) viewer.datum(d);
93458 this.setStyles(context, null, true);
93459 context.container().selectAll('.icon-sign').classed('currentView', false);
93460 if (!d) return this;
93461 var wrap = context.container().select('.photoviewer .osc-wrapper');
93462 var imageWrap = wrap.selectAll('.osc-image-wrap');
93463 var attribution = wrap.selectAll('.photo-attribution').html('');
93464 wrap.transition().duration(100).call(imgZoom.transform, identity$2);
93465 imageWrap.selectAll('.osc-image').remove();
93468 var sequence = _oscCache.sequences[d.sequence_id];
93469 var r = sequence && sequence.rotation || 0;
93470 imageWrap.append('img').attr('class', 'osc-image').attr('src', apibase$1 + '/' + d.imagePath).style('transform', 'rotate(' + r + 'deg)');
93472 if (d.captured_by) {
93473 attribution.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://openstreetcam.org/user/' + encodeURIComponent(d.captured_by)).html('@' + d.captured_by);
93474 attribution.append('span').html('|');
93477 if (d.captured_at) {
93478 attribution.append('span').attr('class', 'captured_at').html(localeDateString(d.captured_at));
93479 attribution.append('span').html('|');
93482 attribution.append('a').attr('class', 'image-link').attr('target', '_blank').attr('href', 'https://openstreetcam.org/details/' + d.sequence_id + '/' + d.sequence_index).html('openstreetcam.org');
93487 function localeDateString(s) {
93488 if (!s) return null;
93494 var d = new Date(s);
93495 if (isNaN(d.getTime())) return null;
93496 return d.toLocaleDateString(_mainLocalizer.localeCode(), options);
93499 getSelectedImage: function getSelectedImage() {
93500 return _oscSelectedImage;
93502 getSequenceKeyForImage: function getSequenceKeyForImage(d) {
93503 return d && d.sequence_id;
93505 // Updates the currently highlighted sequence and selected bubble.
93506 // Reset is only necessary when interacting with the viewport because
93507 // this implicitly changes the currently selected bubble/sequence
93508 setStyles: function setStyles(context, hovered, reset) {
93510 // reset all layers
93511 context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
93512 context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
93515 var hoveredImageKey = hovered && hovered.key;
93516 var hoveredSequenceKey = this.getSequenceKeyForImage(hovered);
93517 var hoveredSequence = hoveredSequenceKey && _oscCache.sequences[hoveredSequenceKey];
93518 var hoveredImageKeys = hoveredSequence && hoveredSequence.images.map(function (d) {
93521 var viewer = context.container().select('.photoviewer');
93522 var selected = viewer.empty() ? undefined : viewer.datum();
93523 var selectedImageKey = selected && selected.key;
93524 var selectedSequenceKey = this.getSequenceKeyForImage(selected);
93525 var selectedSequence = selectedSequenceKey && _oscCache.sequences[selectedSequenceKey];
93526 var selectedImageKeys = selectedSequence && selectedSequence.images.map(function (d) {
93528 }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
93530 var highlightedImageKeys = utilArrayUnion(hoveredImageKeys, selectedImageKeys);
93531 context.container().selectAll('.layer-openstreetcam .viewfield-group').classed('highlighted', function (d) {
93532 return highlightedImageKeys.indexOf(d.key) !== -1;
93533 }).classed('hovered', function (d) {
93534 return d.key === hoveredImageKey;
93535 }).classed('currentView', function (d) {
93536 return d.key === selectedImageKey;
93538 context.container().selectAll('.layer-openstreetcam .sequence').classed('highlighted', function (d) {
93539 return d.properties.key === hoveredSequenceKey;
93540 }).classed('currentView', function (d) {
93541 return d.properties.key === selectedSequenceKey;
93542 }); // update viewfields if needed
93544 context.container().selectAll('.layer-openstreetcam .viewfield-group .viewfield').attr('d', viewfieldPath);
93546 function viewfieldPath() {
93547 var d = this.parentNode.__data__;
93549 if (d.pano && d.key !== selectedImageKey) {
93550 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
93552 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
93558 updateUrlImage: function updateUrlImage(imageKey) {
93559 if (!window.mocha) {
93560 var hash = utilStringQs(window.location.hash);
93563 hash.photo = 'openstreetcam/' + imageKey;
93568 window.location.replace('#' + utilQsString(hash, true));
93571 cache: function cache() {
93576 var hashes$1 = {exports: {}};
93578 (function (module, exports) {
93582 function utf8Encode(str) {
93589 if (str && str.length) {
93592 while ((i += 1) < l) {
93593 /* Decode utf-16 surrogate pairs */
93594 x = str.charCodeAt(i);
93595 y = i + 1 < l ? str.charCodeAt(i + 1) : 0;
93597 if (0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF) {
93598 x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
93601 /* Encode output as utf-8 */
93605 output += String.fromCharCode(x);
93606 } else if (x <= 0x7FF) {
93607 output += String.fromCharCode(0xC0 | x >>> 6 & 0x1F, 0x80 | x & 0x3F);
93608 } else if (x <= 0xFFFF) {
93609 output += String.fromCharCode(0xE0 | x >>> 12 & 0x0F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
93610 } else if (x <= 0x1FFFFF) {
93611 output += String.fromCharCode(0xF0 | x >>> 18 & 0x07, 0x80 | x >>> 12 & 0x3F, 0x80 | x >>> 6 & 0x3F, 0x80 | x & 0x3F);
93619 function utf8Decode(str) {
93627 i = ac = c1 = c2 = c3 = 0;
93629 if (str && str.length) {
93634 c1 = str.charCodeAt(i);
93638 arr[ac] = String.fromCharCode(c1);
93640 } else if (c1 > 191 && c1 < 224) {
93641 c2 = str.charCodeAt(i + 1);
93642 arr[ac] = String.fromCharCode((c1 & 31) << 6 | c2 & 63);
93645 c2 = str.charCodeAt(i + 1);
93646 c3 = str.charCodeAt(i + 2);
93647 arr[ac] = String.fromCharCode((c1 & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
93653 return arr.join('');
93656 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
93657 * to work around bugs in some JS interpreters.
93661 function safe_add(x, y) {
93662 var lsw = (x & 0xFFFF) + (y & 0xFFFF),
93663 msw = (x >> 16) + (y >> 16) + (lsw >> 16);
93664 return msw << 16 | lsw & 0xFFFF;
93667 * Bitwise rotate a 32-bit number to the left.
93671 function bit_rol(num, cnt) {
93672 return num << cnt | num >>> 32 - cnt;
93675 * Convert a raw string to a hex string
93679 function rstr2hex(input, hexcase) {
93680 var hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef',
93686 for (; i < l; i += 1) {
93687 x = input.charCodeAt(i);
93688 output += hex_tab.charAt(x >>> 4 & 0x0F) + hex_tab.charAt(x & 0x0F);
93694 * Convert an array of big-endian words to a string
93698 function binb2rstr(input) {
93700 l = input.length * 32,
93703 for (i = 0; i < l; i += 8) {
93704 output += String.fromCharCode(input[i >> 5] >>> 24 - i % 32 & 0xFF);
93710 * Convert an array of little-endian words to a string
93714 function binl2rstr(input) {
93716 l = input.length * 32,
93719 for (i = 0; i < l; i += 8) {
93720 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
93726 * Convert a raw string to an array of little-endian words
93727 * Characters >255 have their high-byte silently ignored.
93731 function rstr2binl(input) {
93733 l = input.length * 8,
93734 output = Array(input.length >> 2),
93735 lo = output.length;
93737 for (i = 0; i < lo; i += 1) {
93741 for (i = 0; i < l; i += 8) {
93742 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << i % 32;
93748 * Convert a raw string to an array of big-endian words
93749 * Characters >255 have their high-byte silently ignored.
93753 function rstr2binb(input) {
93755 l = input.length * 8,
93756 output = Array(input.length >> 2),
93757 lo = output.length;
93759 for (i = 0; i < lo; i += 1) {
93763 for (i = 0; i < l; i += 8) {
93764 output[i >> 5] |= (input.charCodeAt(i / 8) & 0xFF) << 24 - i % 32;
93770 * Convert a raw string to an arbitrary string encoding
93774 function rstr2any(input, encoding) {
93775 var divisor = encoding.length,
93776 remainders = Array(),
93785 /* Convert to an array of 16-bit big-endian values, forming the dividend */
93787 dividend = Array(Math.ceil(input.length / 2));
93788 ld = dividend.length;
93790 for (i = 0; i < ld; i += 1) {
93791 dividend[i] = input.charCodeAt(i * 2) << 8 | input.charCodeAt(i * 2 + 1);
93794 * Repeatedly perform a long division. The binary array forms the dividend,
93795 * the length of the encoding is the divisor. Once computed, the quotient
93796 * forms the dividend for the next step. We stop when the dividend is zerHashes.
93797 * All remainders are stored for later use.
93801 while (dividend.length > 0) {
93802 quotient = Array();
93805 for (i = 0; i < dividend.length; i += 1) {
93806 x = (x << 16) + dividend[i];
93807 q = Math.floor(x / divisor);
93810 if (quotient.length > 0 || q > 0) {
93811 quotient[quotient.length] = q;
93815 remainders[remainders.length] = x;
93816 dividend = quotient;
93818 /* Convert the remainders to the output string */
93823 for (i = remainders.length - 1; i >= 0; i--) {
93824 output += encoding.charAt(remainders[i]);
93826 /* Append leading zero equivalents */
93829 full_length = Math.ceil(input.length * 8 / (Math.log(encoding.length) / Math.log(2)));
93831 for (i = output.length; i < full_length; i += 1) {
93832 output = encoding[0] + output;
93838 * Convert a raw string to a base-64 string
93842 function rstr2b64(input, b64pad) {
93843 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
93845 len = input.length,
93849 b64pad = b64pad || '=';
93851 for (i = 0; i < len; i += 3) {
93852 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
93854 for (j = 0; j < 4; j += 1) {
93855 if (i * 8 + j * 6 > input.length * 8) {
93858 output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
93868 * @property {String} version
93878 Base64: function Base64() {
93879 // private properties
93880 var tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
93882 // URL encoding support @todo
93883 utf8 = true; // by default enable UTF-8 support encoding
93884 // public method for encoding
93886 this.encode = function (input) {
93891 len = input.length;
93893 input = utf8 ? utf8Encode(input) : input;
93895 for (i = 0; i < len; i += 3) {
93896 triplet = input.charCodeAt(i) << 16 | (i + 1 < len ? input.charCodeAt(i + 1) << 8 : 0) | (i + 2 < len ? input.charCodeAt(i + 2) : 0);
93898 for (j = 0; j < 4; j += 1) {
93899 if (i * 8 + j * 6 > len * 8) {
93902 output += tab.charAt(triplet >>> 6 * (3 - j) & 0x3F);
93908 }; // public method for decoding
93911 this.decode = function (input) {
93912 // var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
93931 input = input.replace(new RegExp('\\' + pad, 'gi'), ''); // use '='
93935 // unpack four hexets into three octets using index points in b64
93936 h1 = tab.indexOf(input.charAt(i += 1));
93937 h2 = tab.indexOf(input.charAt(i += 1));
93938 h3 = tab.indexOf(input.charAt(i += 1));
93939 h4 = tab.indexOf(input.charAt(i += 1));
93940 bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
93941 o1 = bits >> 16 & 0xff;
93942 o2 = bits >> 8 & 0xff;
93947 arr[ac] = String.fromCharCode(o1);
93948 } else if (h4 === 64) {
93949 arr[ac] = String.fromCharCode(o1, o2);
93951 arr[ac] = String.fromCharCode(o1, o2, o3);
93953 } while (i < input.length);
93955 dec = arr.join('');
93956 dec = utf8 ? utf8Decode(dec) : dec;
93958 }; // set custom pad string
93961 this.setPad = function (str) {
93964 }; // set custom tab string characters
93967 this.setTab = function (str) {
93972 this.setUTF8 = function (bool) {
93973 if (typeof bool === 'boolean') {
93982 * CRC-32 calculation
93986 * @param {String} str Input String
93989 CRC32: function CRC32(str) {
93996 str = utf8Encode(str);
93997 table = ['00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 ', '79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 ', '84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F ', '63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD ', 'A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC ', '51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 ', 'B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 ', '06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 ', 'E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 ', '12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 ', 'D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 ', '33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 ', 'CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 ', '9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E ', '7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D ', '806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 ', '60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA ', 'AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 ', '5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 ', 'B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 ', '05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 ', 'F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA ', '11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 ', 'D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F ', '30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E ', 'C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D'].join('');
94000 for (i = 0, iTop = str.length; i < iTop; i += 1) {
94001 y = (crc ^ str.charCodeAt(i)) & 0xFF;
94002 x = '0x' + table.substr(y * 9, 8);
94003 crc = crc >>> 8 ^ x;
94004 } // always return a positive number (that's what >>> 0 does)
94007 return (crc ^ -1) >>> 0;
94014 * @param {Object} [config]
94016 * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
94017 * Digest Algorithm, as defined in RFC 1321.
94018 * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
94019 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94020 * See <http://pajhome.org.uk/crypt/md5> for more infHashes.
94022 MD5: function MD5(options) {
94024 * Private config properties. You may need to tweak these to be compatible with
94025 * the server-side, but the defaults work in most cases.
94026 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
94028 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
94029 // hexadecimal output case format. false - lowercase; true - uppercase
94030 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94031 // base-64 pad character. Defaults to '=' for strict RFC compliance
94032 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
94033 // privileged (public) methods
94035 this.hex = function (s) {
94036 return rstr2hex(rstr(s), hexcase);
94039 this.b64 = function (s) {
94040 return rstr2b64(rstr(s), b64pad);
94043 this.any = function (s, e) {
94044 return rstr2any(rstr(s), e);
94047 this.raw = function (s) {
94051 this.hex_hmac = function (k, d) {
94052 return rstr2hex(rstr_hmac(k, d), hexcase);
94055 this.b64_hmac = function (k, d) {
94056 return rstr2b64(rstr_hmac(k, d), b64pad);
94059 this.any_hmac = function (k, d, e) {
94060 return rstr2any(rstr_hmac(k, d), e);
94063 * Perform a simple self-test to see if the VM is working
94064 * @return {String} Hexadecimal hash sample
94068 this.vm_test = function () {
94069 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94072 * Enable/disable uppercase hexadecimal returned string
94074 * @return {Object} this
94078 this.setUpperCase = function (a) {
94079 if (typeof a === 'boolean') {
94086 * Defines a base64 pad string
94087 * @param {String} Pad
94088 * @return {Object} this
94092 this.setPad = function (a) {
94093 b64pad = a || b64pad;
94097 * Defines a base64 pad string
94099 * @return {Object} [this]
94103 this.setUTF8 = function (a) {
94104 if (typeof a === 'boolean') {
94109 }; // private methods
94112 * Calculate the MD5 of a raw string
94117 s = utf8 ? utf8Encode(s) : s;
94118 return binl2rstr(binl(rstr2binl(s), s.length * 8));
94121 * Calculate the HMAC-MD5, of a key and some data (raw strings)
94125 function rstr_hmac(key, data) {
94126 var bkey, ipad, opad, hash, i;
94127 key = utf8 ? utf8Encode(key) : key;
94128 data = utf8 ? utf8Encode(data) : data;
94129 bkey = rstr2binl(key);
94131 if (bkey.length > 16) {
94132 bkey = binl(bkey, key.length * 8);
94135 ipad = Array(16), opad = Array(16);
94137 for (i = 0; i < 16; i += 1) {
94138 ipad[i] = bkey[i] ^ 0x36363636;
94139 opad[i] = bkey[i] ^ 0x5C5C5C5C;
94142 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
94143 return binl2rstr(binl(opad.concat(hash), 512 + 128));
94146 * Calculate the MD5 of an array of little-endian words, and a bit length.
94150 function binl(x, len) {
94160 /* append padding */
94162 x[len >> 5] |= 0x80 << len % 32;
94163 x[(len + 64 >>> 9 << 4) + 14] = len;
94165 for (i = 0; i < x.length; i += 16) {
94170 a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936);
94171 d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586);
94172 c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819);
94173 b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330);
94174 a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897);
94175 d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426);
94176 c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341);
94177 b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983);
94178 a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416);
94179 d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417);
94180 c = md5_ff(c, d, a, b, x[i + 10], 17, -42063);
94181 b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162);
94182 a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682);
94183 d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101);
94184 c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290);
94185 b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329);
94186 a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510);
94187 d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632);
94188 c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713);
94189 b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302);
94190 a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691);
94191 d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083);
94192 c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335);
94193 b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848);
94194 a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438);
94195 d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690);
94196 c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961);
94197 b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501);
94198 a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467);
94199 d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784);
94200 c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473);
94201 b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734);
94202 a = md5_hh(a, b, c, d, x[i + 5], 4, -378558);
94203 d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463);
94204 c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562);
94205 b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556);
94206 a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060);
94207 d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353);
94208 c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632);
94209 b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640);
94210 a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174);
94211 d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222);
94212 c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979);
94213 b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189);
94214 a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487);
94215 d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835);
94216 c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520);
94217 b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651);
94218 a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844);
94219 d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415);
94220 c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905);
94221 b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055);
94222 a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571);
94223 d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606);
94224 c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523);
94225 b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799);
94226 a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359);
94227 d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744);
94228 c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380);
94229 b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649);
94230 a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070);
94231 d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379);
94232 c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259);
94233 b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551);
94234 a = safe_add(a, olda);
94235 b = safe_add(b, oldb);
94236 c = safe_add(c, oldc);
94237 d = safe_add(d, oldd);
94240 return Array(a, b, c, d);
94243 * These functions implement the four basic operations the algorithm uses.
94247 function md5_cmn(q, a, b, x, s, t) {
94248 return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b);
94251 function md5_ff(a, b, c, d, x, s, t) {
94252 return md5_cmn(b & c | ~b & d, a, b, x, s, t);
94255 function md5_gg(a, b, c, d, x, s, t) {
94256 return md5_cmn(b & d | c & ~d, a, b, x, s, t);
94259 function md5_hh(a, b, c, d, x, s, t) {
94260 return md5_cmn(b ^ c ^ d, a, b, x, s, t);
94263 function md5_ii(a, b, c, d, x, s, t) {
94264 return md5_cmn(c ^ (b | ~d), a, b, x, s, t);
94270 * @class Hashes.SHA1
94271 * @param {Object} [config]
94274 * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined in FIPS 180-1
94275 * Version 2.2 Copyright Paul Johnston 2000 - 2009.
94276 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94277 * See http://pajhome.org.uk/crypt/md5 for details.
94279 SHA1: function SHA1(options) {
94281 * Private config properties. You may need to tweak these to be compatible with
94282 * the server-side, but the defaults work in most cases.
94283 * See {@link Hashes.MD5#method-setUpperCase} and {@link Hashes.SHA1#method-setUpperCase}
94285 var hexcase = options && typeof options.uppercase === 'boolean' ? options.uppercase : false,
94286 // hexadecimal output case format. false - lowercase; true - uppercase
94287 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94288 // base-64 pad character. Defaults to '=' for strict RFC compliance
94289 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true; // enable/disable utf8 encoding
94292 this.hex = function (s) {
94293 return rstr2hex(rstr(s), hexcase);
94296 this.b64 = function (s) {
94297 return rstr2b64(rstr(s), b64pad);
94300 this.any = function (s, e) {
94301 return rstr2any(rstr(s), e);
94304 this.raw = function (s) {
94308 this.hex_hmac = function (k, d) {
94309 return rstr2hex(rstr_hmac(k, d));
94312 this.b64_hmac = function (k, d) {
94313 return rstr2b64(rstr_hmac(k, d), b64pad);
94316 this.any_hmac = function (k, d, e) {
94317 return rstr2any(rstr_hmac(k, d), e);
94320 * Perform a simple self-test to see if the VM is working
94321 * @return {String} Hexadecimal hash sample
94326 this.vm_test = function () {
94327 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94330 * @description Enable/disable uppercase hexadecimal returned string
94332 * @return {Object} this
94337 this.setUpperCase = function (a) {
94338 if (typeof a === 'boolean') {
94345 * @description Defines a base64 pad string
94346 * @param {string} Pad
94347 * @return {Object} this
94352 this.setPad = function (a) {
94353 b64pad = a || b64pad;
94357 * @description Defines a base64 pad string
94359 * @return {Object} this
94364 this.setUTF8 = function (a) {
94365 if (typeof a === 'boolean') {
94370 }; // private methods
94373 * Calculate the SHA-512 of a raw string
94378 s = utf8 ? utf8Encode(s) : s;
94379 return binb2rstr(binb(rstr2binb(s), s.length * 8));
94382 * Calculate the HMAC-SHA1 of a key and some data (raw strings)
94386 function rstr_hmac(key, data) {
94387 var bkey, ipad, opad, i, hash;
94388 key = utf8 ? utf8Encode(key) : key;
94389 data = utf8 ? utf8Encode(data) : data;
94390 bkey = rstr2binb(key);
94392 if (bkey.length > 16) {
94393 bkey = binb(bkey, key.length * 8);
94396 ipad = Array(16), opad = Array(16);
94398 for (i = 0; i < 16; i += 1) {
94399 ipad[i] = bkey[i] ^ 0x36363636;
94400 opad[i] = bkey[i] ^ 0x5C5C5C5C;
94403 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
94404 return binb2rstr(binb(opad.concat(hash), 512 + 160));
94407 * Calculate the SHA-1 of an array of big-endian words, and a bit length
94411 function binb(x, len) {
94426 /* append padding */
94428 x[len >> 5] |= 0x80 << 24 - len % 32;
94429 x[(len + 64 >> 9 << 4) + 15] = len;
94431 for (i = 0; i < x.length; i += 16) {
94438 for (j = 0; j < 80; j += 1) {
94442 w[j] = bit_rol(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
94445 t = safe_add(safe_add(bit_rol(a, 5), sha1_ft(j, b, c, d)), safe_add(safe_add(e, w[j]), sha1_kt(j)));
94448 c = bit_rol(b, 30);
94453 a = safe_add(a, olda);
94454 b = safe_add(b, oldb);
94455 c = safe_add(c, oldc);
94456 d = safe_add(d, oldd);
94457 e = safe_add(e, olde);
94460 return Array(a, b, c, d, e);
94463 * Perform the appropriate triplet combination function for the current
94468 function sha1_ft(t, b, c, d) {
94470 return b & c | ~b & d;
94478 return b & c | b & d | c & d;
94484 * Determine the appropriate additive constant for the current iteration
94488 function sha1_kt(t) {
94489 return t < 20 ? 1518500249 : t < 40 ? 1859775393 : t < 60 ? -1894007588 : -899497514;
94494 * @class Hashes.SHA256
94497 * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined in FIPS 180-2
94498 * Version 2.2 Copyright Angel Marin, Paul Johnston 2000 - 2009.
94499 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94500 * See http://pajhome.org.uk/crypt/md5 for details.
94501 * Also http://anmar.eu.org/projects/jssha2/
94503 SHA256: function SHA256(options) {
94505 * Private properties configuration variables. You may need to tweak these to be compatible with
94506 * the server-side, but the defaults work in most cases.
94507 * @see this.setUpperCase() method
94508 * @see this.setPad() method
94510 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
94511 var // hexadecimal output case format. false - lowercase; true - uppercase */
94512 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94514 /* base-64 pad character. Default '=' for strict RFC compliance */
94515 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
94517 /* enable/disable utf8 encoding */
94519 /* privileged (public) methods */
94521 this.hex = function (s) {
94522 return rstr2hex(rstr(s, utf8));
94525 this.b64 = function (s) {
94526 return rstr2b64(rstr(s, utf8), b64pad);
94529 this.any = function (s, e) {
94530 return rstr2any(rstr(s, utf8), e);
94533 this.raw = function (s) {
94534 return rstr(s, utf8);
94537 this.hex_hmac = function (k, d) {
94538 return rstr2hex(rstr_hmac(k, d));
94541 this.b64_hmac = function (k, d) {
94542 return rstr2b64(rstr_hmac(k, d), b64pad);
94545 this.any_hmac = function (k, d, e) {
94546 return rstr2any(rstr_hmac(k, d), e);
94549 * Perform a simple self-test to see if the VM is working
94550 * @return {String} Hexadecimal hash sample
94555 this.vm_test = function () {
94556 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94559 * Enable/disable uppercase hexadecimal returned string
94561 * @return {Object} this
94566 this.setUpperCase = function (a) {
94571 * @description Defines a base64 pad string
94572 * @param {string} Pad
94573 * @return {Object} this
94578 this.setPad = function (a) {
94579 b64pad = a || b64pad;
94583 * Defines a base64 pad string
94585 * @return {Object} this
94590 this.setUTF8 = function (a) {
94591 if (typeof a === 'boolean') {
94596 }; // private methods
94599 * Calculate the SHA-512 of a raw string
94603 function rstr(s, utf8) {
94604 s = utf8 ? utf8Encode(s) : s;
94605 return binb2rstr(binb(rstr2binb(s), s.length * 8));
94608 * Calculate the HMAC-sha256 of a key and some data (raw strings)
94612 function rstr_hmac(key, data) {
94613 key = utf8 ? utf8Encode(key) : key;
94614 data = utf8 ? utf8Encode(data) : data;
94617 bkey = rstr2binb(key),
94621 if (bkey.length > 16) {
94622 bkey = binb(bkey, key.length * 8);
94625 for (; i < 16; i += 1) {
94626 ipad[i] = bkey[i] ^ 0x36363636;
94627 opad[i] = bkey[i] ^ 0x5C5C5C5C;
94630 hash = binb(ipad.concat(rstr2binb(data)), 512 + data.length * 8);
94631 return binb2rstr(binb(opad.concat(hash), 512 + 256));
94634 * Main sha256 function, with its support functions
94638 function sha256_S(X, n) {
94639 return X >>> n | X << 32 - n;
94642 function sha256_R(X, n) {
94646 function sha256_Ch(x, y, z) {
94647 return x & y ^ ~x & z;
94650 function sha256_Maj(x, y, z) {
94651 return x & y ^ x & z ^ y & z;
94654 function sha256_Sigma0256(x) {
94655 return sha256_S(x, 2) ^ sha256_S(x, 13) ^ sha256_S(x, 22);
94658 function sha256_Sigma1256(x) {
94659 return sha256_S(x, 6) ^ sha256_S(x, 11) ^ sha256_S(x, 25);
94662 function sha256_Gamma0256(x) {
94663 return sha256_S(x, 7) ^ sha256_S(x, 18) ^ sha256_R(x, 3);
94666 function sha256_Gamma1256(x) {
94667 return sha256_S(x, 17) ^ sha256_S(x, 19) ^ sha256_R(x, 10);
94670 sha256_K = [1116352408, 1899447441, -1245643825, -373957723, 961987163, 1508970993, -1841331548, -1424204075, -670586216, 310598401, 607225278, 1426881987, 1925078388, -2132889090, -1680079193, -1046744716, -459576895, -272742522, 264347078, 604807628, 770255983, 1249150122, 1555081692, 1996064986, -1740746414, -1473132947, -1341970488, -1084653625, -958395405, -710438585, 113926993, 338241895, 666307205, 773529912, 1294757372, 1396182291, 1695183700, 1986661051, -2117940946, -1838011259, -1564481375, -1474664885, -1035236496, -949202525, -778901479, -694614492, -200395387, 275423344, 430227734, 506948616, 659060556, 883997877, 958139571, 1322822218, 1537002063, 1747873779, 1955562222, 2024104815, -2067236844, -1933114872, -1866530822, -1538233109, -1090935817, -965641998];
94672 function binb(m, l) {
94673 var HASH = [1779033703, -1150833019, 1013904242, -1521486534, 1359893119, -1694144372, 528734635, 1541459225];
94674 var W = new Array(64);
94675 var a, b, c, d, e, f, g, h;
94677 /* append padding */
94679 m[l >> 5] |= 0x80 << 24 - l % 32;
94680 m[(l + 64 >> 9 << 4) + 15] = l;
94682 for (i = 0; i < m.length; i += 16) {
94692 for (j = 0; j < 64; j += 1) {
94696 W[j] = safe_add(safe_add(safe_add(sha256_Gamma1256(W[j - 2]), W[j - 7]), sha256_Gamma0256(W[j - 15])), W[j - 16]);
94699 T1 = safe_add(safe_add(safe_add(safe_add(h, sha256_Sigma1256(e)), sha256_Ch(e, f, g)), sha256_K[j]), W[j]);
94700 T2 = safe_add(sha256_Sigma0256(a), sha256_Maj(a, b, c));
94704 e = safe_add(d, T1);
94708 a = safe_add(T1, T2);
94711 HASH[0] = safe_add(a, HASH[0]);
94712 HASH[1] = safe_add(b, HASH[1]);
94713 HASH[2] = safe_add(c, HASH[2]);
94714 HASH[3] = safe_add(d, HASH[3]);
94715 HASH[4] = safe_add(e, HASH[4]);
94716 HASH[5] = safe_add(f, HASH[5]);
94717 HASH[6] = safe_add(g, HASH[6]);
94718 HASH[7] = safe_add(h, HASH[7]);
94726 * @class Hashes.SHA512
94729 * A JavaScript implementation of the Secure Hash Algorithm, SHA-512, as defined in FIPS 180-2
94730 * Version 2.2 Copyright Anonymous Contributor, Paul Johnston 2000 - 2009.
94731 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
94732 * See http://pajhome.org.uk/crypt/md5 for details.
94734 SHA512: function SHA512(options) {
94736 * Private properties configuration variables. You may need to tweak these to be compatible with
94737 * the server-side, but the defaults work in most cases.
94738 * @see this.setUpperCase() method
94739 * @see this.setPad() method
94741 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
94743 var /* hexadecimal output case format. false - lowercase; true - uppercase */
94744 b64pad = options && typeof options.pad === 'string' ? options.pad : '=',
94746 /* base-64 pad character. Default '=' for strict RFC compliance */
94747 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
94749 /* enable/disable utf8 encoding */
94751 /* privileged (public) methods */
94753 this.hex = function (s) {
94754 return rstr2hex(rstr(s));
94757 this.b64 = function (s) {
94758 return rstr2b64(rstr(s), b64pad);
94761 this.any = function (s, e) {
94762 return rstr2any(rstr(s), e);
94765 this.raw = function (s) {
94769 this.hex_hmac = function (k, d) {
94770 return rstr2hex(rstr_hmac(k, d));
94773 this.b64_hmac = function (k, d) {
94774 return rstr2b64(rstr_hmac(k, d), b64pad);
94777 this.any_hmac = function (k, d, e) {
94778 return rstr2any(rstr_hmac(k, d), e);
94781 * Perform a simple self-test to see if the VM is working
94782 * @return {String} Hexadecimal hash sample
94787 this.vm_test = function () {
94788 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
94791 * @description Enable/disable uppercase hexadecimal returned string
94793 * @return {Object} this
94798 this.setUpperCase = function (a) {
94803 * @description Defines a base64 pad string
94804 * @param {string} Pad
94805 * @return {Object} this
94810 this.setPad = function (a) {
94811 b64pad = a || b64pad;
94815 * @description Defines a base64 pad string
94817 * @return {Object} this
94822 this.setUTF8 = function (a) {
94823 if (typeof a === 'boolean') {
94829 /* private methods */
94832 * Calculate the SHA-512 of a raw string
94837 s = utf8 ? utf8Encode(s) : s;
94838 return binb2rstr(binb(rstr2binb(s), s.length * 8));
94841 * Calculate the HMAC-SHA-512 of a key and some data (raw strings)
94845 function rstr_hmac(key, data) {
94846 key = utf8 ? utf8Encode(key) : key;
94847 data = utf8 ? utf8Encode(data) : data;
94850 bkey = rstr2binb(key),
94854 if (bkey.length > 32) {
94855 bkey = binb(bkey, key.length * 8);
94858 for (; i < 32; i += 1) {
94859 ipad[i] = bkey[i] ^ 0x36363636;
94860 opad[i] = bkey[i] ^ 0x5C5C5C5C;
94863 hash = binb(ipad.concat(rstr2binb(data)), 1024 + data.length * 8);
94864 return binb2rstr(binb(opad.concat(hash), 1024 + 512));
94867 * Calculate the SHA-512 of an array of big-endian dwords, and a bit length
94871 function binb(x, len) {
94876 hash = new Array(16),
94877 //Initial hash values
94878 H = [new int64(0x6a09e667, -205731576), new int64(-1150833019, -2067093701), new int64(0x3c6ef372, -23791573), new int64(-1521486534, 0x5f1d36f1), new int64(0x510e527f, -1377402159), new int64(-1694144372, 0x2b3e6c1f), new int64(0x1f83d9ab, -79577749), new int64(0x5be0cd19, 0x137e2179)],
94879 T1 = new int64(0, 0),
94880 T2 = new int64(0, 0),
94881 a = new int64(0, 0),
94882 b = new int64(0, 0),
94883 c = new int64(0, 0),
94884 d = new int64(0, 0),
94885 e = new int64(0, 0),
94886 f = new int64(0, 0),
94887 g = new int64(0, 0),
94888 h = new int64(0, 0),
94889 //Temporary variables not specified by the document
94890 s0 = new int64(0, 0),
94891 s1 = new int64(0, 0),
94892 Ch = new int64(0, 0),
94893 Maj = new int64(0, 0),
94894 r1 = new int64(0, 0),
94895 r2 = new int64(0, 0),
94896 r3 = new int64(0, 0);
94898 if (sha512_k === undefined) {
94900 sha512_k = [new int64(0x428a2f98, -685199838), new int64(0x71374491, 0x23ef65cd), new int64(-1245643825, -330482897), new int64(-373957723, -2121671748), new int64(0x3956c25b, -213338824), new int64(0x59f111f1, -1241133031), new int64(-1841331548, -1357295717), new int64(-1424204075, -630357736), new int64(-670586216, -1560083902), new int64(0x12835b01, 0x45706fbe), new int64(0x243185be, 0x4ee4b28c), new int64(0x550c7dc3, -704662302), new int64(0x72be5d74, -226784913), new int64(-2132889090, 0x3b1696b1), new int64(-1680079193, 0x25c71235), new int64(-1046744716, -815192428), new int64(-459576895, -1628353838), new int64(-272742522, 0x384f25e3), new int64(0xfc19dc6, -1953704523), new int64(0x240ca1cc, 0x77ac9c65), new int64(0x2de92c6f, 0x592b0275), new int64(0x4a7484aa, 0x6ea6e483), new int64(0x5cb0a9dc, -1119749164), new int64(0x76f988da, -2096016459), new int64(-1740746414, -295247957), new int64(-1473132947, 0x2db43210), new int64(-1341970488, -1728372417), new int64(-1084653625, -1091629340), new int64(-958395405, 0x3da88fc2), new int64(-710438585, -1828018395), new int64(0x6ca6351, -536640913), new int64(0x14292967, 0xa0e6e70), new int64(0x27b70a85, 0x46d22ffc), new int64(0x2e1b2138, 0x5c26c926), new int64(0x4d2c6dfc, 0x5ac42aed), new int64(0x53380d13, -1651133473), new int64(0x650a7354, -1951439906), new int64(0x766a0abb, 0x3c77b2a8), new int64(-2117940946, 0x47edaee6), new int64(-1838011259, 0x1482353b), new int64(-1564481375, 0x4cf10364), new int64(-1474664885, -1136513023), new int64(-1035236496, -789014639), new int64(-949202525, 0x654be30), new int64(-778901479, -688958952), new int64(-694614492, 0x5565a910), new int64(-200395387, 0x5771202a), new int64(0x106aa070, 0x32bbd1b8), new int64(0x19a4c116, -1194143544), new int64(0x1e376c08, 0x5141ab53), new int64(0x2748774c, -544281703), new int64(0x34b0bcb5, -509917016), new int64(0x391c0cb3, -976659869), new int64(0x4ed8aa4a, -482243893), new int64(0x5b9cca4f, 0x7763e373), new int64(0x682e6ff3, -692930397), new int64(0x748f82ee, 0x5defb2fc), new int64(0x78a5636f, 0x43172f60), new int64(-2067236844, -1578062990), new int64(-1933114872, 0x1a6439ec), new int64(-1866530822, 0x23631e28), new int64(-1538233109, -561857047), new int64(-1090935817, -1295615723), new int64(-965641998, -479046869), new int64(-903397682, -366583396), new int64(-779700025, 0x21c0c207), new int64(-354779690, -840897762), new int64(-176337025, -294727304), new int64(0x6f067aa, 0x72176fba), new int64(0xa637dc5, -1563912026), new int64(0x113f9804, -1090974290), new int64(0x1b710b35, 0x131c471b), new int64(0x28db77f5, 0x23047d84), new int64(0x32caab7b, 0x40c72493), new int64(0x3c9ebe0a, 0x15c9bebc), new int64(0x431d67c4, -1676669620), new int64(0x4cc5d4be, -885112138), new int64(0x597f299c, -60457430), new int64(0x5fcb6fab, 0x3ad6faec), new int64(0x6c44198c, 0x4a475817)];
94903 for (i = 0; i < 80; i += 1) {
94904 W[i] = new int64(0, 0);
94905 } // append padding to the source string. The format is described in the FIPS.
94908 x[len >> 5] |= 0x80 << 24 - (len & 0x1f);
94909 x[(len + 128 >> 10 << 5) + 31] = len;
94912 for (i = 0; i < l; i += 32) {
94913 //32 dwords is the block size
94914 int64copy(a, H[0]);
94915 int64copy(b, H[1]);
94916 int64copy(c, H[2]);
94917 int64copy(d, H[3]);
94918 int64copy(e, H[4]);
94919 int64copy(f, H[5]);
94920 int64copy(g, H[6]);
94921 int64copy(h, H[7]);
94923 for (j = 0; j < 16; j += 1) {
94924 W[j].h = x[i + 2 * j];
94925 W[j].l = x[i + 2 * j + 1];
94928 for (j = 16; j < 80; j += 1) {
94930 int64rrot(r1, W[j - 2], 19);
94931 int64revrrot(r2, W[j - 2], 29);
94932 int64shr(r3, W[j - 2], 6);
94933 s1.l = r1.l ^ r2.l ^ r3.l;
94934 s1.h = r1.h ^ r2.h ^ r3.h; //sigma0
94936 int64rrot(r1, W[j - 15], 1);
94937 int64rrot(r2, W[j - 15], 8);
94938 int64shr(r3, W[j - 15], 7);
94939 s0.l = r1.l ^ r2.l ^ r3.l;
94940 s0.h = r1.h ^ r2.h ^ r3.h;
94941 int64add4(W[j], s1, W[j - 7], s0, W[j - 16]);
94944 for (j = 0; j < 80; j += 1) {
94946 Ch.l = e.l & f.l ^ ~e.l & g.l;
94947 Ch.h = e.h & f.h ^ ~e.h & g.h; //Sigma1
94949 int64rrot(r1, e, 14);
94950 int64rrot(r2, e, 18);
94951 int64revrrot(r3, e, 9);
94952 s1.l = r1.l ^ r2.l ^ r3.l;
94953 s1.h = r1.h ^ r2.h ^ r3.h; //Sigma0
94955 int64rrot(r1, a, 28);
94956 int64revrrot(r2, a, 2);
94957 int64revrrot(r3, a, 7);
94958 s0.l = r1.l ^ r2.l ^ r3.l;
94959 s0.h = r1.h ^ r2.h ^ r3.h; //Maj
94961 Maj.l = a.l & b.l ^ a.l & c.l ^ b.l & c.l;
94962 Maj.h = a.h & b.h ^ a.h & c.h ^ b.h & c.h;
94963 int64add5(T1, h, s1, Ch, sha512_k[j], W[j]);
94964 int64add(T2, s0, Maj);
94968 int64add(e, d, T1);
94972 int64add(a, T1, T2);
94975 int64add(H[0], H[0], a);
94976 int64add(H[1], H[1], b);
94977 int64add(H[2], H[2], c);
94978 int64add(H[3], H[3], d);
94979 int64add(H[4], H[4], e);
94980 int64add(H[5], H[5], f);
94981 int64add(H[6], H[6], g);
94982 int64add(H[7], H[7], h);
94983 } //represent the hash as an array of 32-bit dwords
94986 for (i = 0; i < 8; i += 1) {
94987 hash[2 * i] = H[i].h;
94988 hash[2 * i + 1] = H[i].l;
94992 } //A constructor for 64-bit numbers
94995 function int64(h, l) {
94997 this.l = l; //this.toString = int64toString;
94998 } //Copies src into dst, assuming both are 64-bit numbers
95001 function int64copy(dst, src) {
95004 } //Right-rotates a 64-bit number by shift
95005 //Won't handle cases of shift>=32
95006 //The function revrrot() is for that
95009 function int64rrot(dst, x, shift) {
95010 dst.l = x.l >>> shift | x.h << 32 - shift;
95011 dst.h = x.h >>> shift | x.l << 32 - shift;
95012 } //Reverses the dwords of the source and then rotates right by shift.
95013 //This is equivalent to rotation by 32+shift
95016 function int64revrrot(dst, x, shift) {
95017 dst.l = x.h >>> shift | x.l << 32 - shift;
95018 dst.h = x.l >>> shift | x.h << 32 - shift;
95019 } //Bitwise-shifts right a 64-bit number by shift
95020 //Won't handle shift>=32, but it's never needed in SHA512
95023 function int64shr(dst, x, shift) {
95024 dst.l = x.l >>> shift | x.h << 32 - shift;
95025 dst.h = x.h >>> shift;
95026 } //Adds two 64-bit numbers
95027 //Like the original implementation, does not rely on 32-bit operations
95030 function int64add(dst, x, y) {
95031 var w0 = (x.l & 0xffff) + (y.l & 0xffff);
95032 var w1 = (x.l >>> 16) + (y.l >>> 16) + (w0 >>> 16);
95033 var w2 = (x.h & 0xffff) + (y.h & 0xffff) + (w1 >>> 16);
95034 var w3 = (x.h >>> 16) + (y.h >>> 16) + (w2 >>> 16);
95035 dst.l = w0 & 0xffff | w1 << 16;
95036 dst.h = w2 & 0xffff | w3 << 16;
95037 } //Same, except with 4 addends. Works faster than adding them one by one.
95040 function int64add4(dst, a, b, c, d) {
95041 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff);
95042 var w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (w0 >>> 16);
95043 var w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (w1 >>> 16);
95044 var w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (w2 >>> 16);
95045 dst.l = w0 & 0xffff | w1 << 16;
95046 dst.h = w2 & 0xffff | w3 << 16;
95047 } //Same, except with 5 addends
95050 function int64add5(dst, a, b, c, d, e) {
95051 var w0 = (a.l & 0xffff) + (b.l & 0xffff) + (c.l & 0xffff) + (d.l & 0xffff) + (e.l & 0xffff),
95052 w1 = (a.l >>> 16) + (b.l >>> 16) + (c.l >>> 16) + (d.l >>> 16) + (e.l >>> 16) + (w0 >>> 16),
95053 w2 = (a.h & 0xffff) + (b.h & 0xffff) + (c.h & 0xffff) + (d.h & 0xffff) + (e.h & 0xffff) + (w1 >>> 16),
95054 w3 = (a.h >>> 16) + (b.h >>> 16) + (c.h >>> 16) + (d.h >>> 16) + (e.h >>> 16) + (w2 >>> 16);
95055 dst.l = w0 & 0xffff | w1 << 16;
95056 dst.h = w2 & 0xffff | w3 << 16;
95061 * @class Hashes.RMD160
95063 * @param {Object} [config]
95065 * A JavaScript implementation of the RIPEMD-160 Algorithm
95066 * Version 2.2 Copyright Jeremy Lin, Paul Johnston 2000 - 2009.
95067 * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
95068 * See http://pajhome.org.uk/crypt/md5 for details.
95069 * Also http://www.ocf.berkeley.edu/~jjlin/jsotp/
95071 RMD160: function RMD160(options) {
95073 * Private properties configuration variables. You may need to tweak these to be compatible with
95074 * the server-side, but the defaults work in most cases.
95075 * @see this.setUpperCase() method
95076 * @see this.setPad() method
95078 options && typeof options.uppercase === 'boolean' ? options.uppercase : false;
95080 var /* hexadecimal output case format. false - lowercase; true - uppercase */
95081 b64pad = options && typeof options.pad === 'string' ? options.pa : '=',
95083 /* base-64 pad character. Default '=' for strict RFC compliance */
95084 utf8 = options && typeof options.utf8 === 'boolean' ? options.utf8 : true,
95086 /* enable/disable utf8 encoding */
95087 rmd160_r1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13],
95088 rmd160_r2 = [5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11],
95089 rmd160_s1 = [11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6],
95090 rmd160_s2 = [8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11];
95091 /* privileged (public) methods */
95093 this.hex = function (s) {
95094 return rstr2hex(rstr(s));
95097 this.b64 = function (s) {
95098 return rstr2b64(rstr(s), b64pad);
95101 this.any = function (s, e) {
95102 return rstr2any(rstr(s), e);
95105 this.raw = function (s) {
95109 this.hex_hmac = function (k, d) {
95110 return rstr2hex(rstr_hmac(k, d));
95113 this.b64_hmac = function (k, d) {
95114 return rstr2b64(rstr_hmac(k, d), b64pad);
95117 this.any_hmac = function (k, d, e) {
95118 return rstr2any(rstr_hmac(k, d), e);
95121 * Perform a simple self-test to see if the VM is working
95122 * @return {String} Hexadecimal hash sample
95127 this.vm_test = function () {
95128 return hex('abc').toLowerCase() === '900150983cd24fb0d6963f7d28e17f72';
95131 * @description Enable/disable uppercase hexadecimal returned string
95133 * @return {Object} this
95138 this.setUpperCase = function (a) {
95143 * @description Defines a base64 pad string
95144 * @param {string} Pad
95145 * @return {Object} this
95150 this.setPad = function (a) {
95151 if (typeof a !== 'undefined') {
95158 * @description Defines a base64 pad string
95160 * @return {Object} this
95165 this.setUTF8 = function (a) {
95166 if (typeof a === 'boolean') {
95172 /* private methods */
95175 * Calculate the rmd160 of a raw string
95180 s = utf8 ? utf8Encode(s) : s;
95181 return binl2rstr(binl(rstr2binl(s), s.length * 8));
95184 * Calculate the HMAC-rmd160 of a key and some data (raw strings)
95188 function rstr_hmac(key, data) {
95189 key = utf8 ? utf8Encode(key) : key;
95190 data = utf8 ? utf8Encode(data) : data;
95193 bkey = rstr2binl(key),
95197 if (bkey.length > 16) {
95198 bkey = binl(bkey, key.length * 8);
95201 for (i = 0; i < 16; i += 1) {
95202 ipad[i] = bkey[i] ^ 0x36363636;
95203 opad[i] = bkey[i] ^ 0x5C5C5C5C;
95206 hash = binl(ipad.concat(rstr2binl(data)), 512 + data.length * 8);
95207 return binl2rstr(binl(opad.concat(hash), 512 + 160));
95210 * Convert an array of little-endian words to a string
95214 function binl2rstr(input) {
95217 l = input.length * 32;
95219 for (i = 0; i < l; i += 8) {
95220 output += String.fromCharCode(input[i >> 5] >>> i % 32 & 0xFF);
95226 * Calculate the RIPE-MD160 of an array of little-endian words, and a bit length.
95230 function binl(x, len) {
95250 /* append padding */
95252 x[len >> 5] |= 0x80 << len % 32;
95253 x[(len + 64 >>> 9 << 4) + 14] = len;
95256 for (i = 0; i < l; i += 16) {
95263 for (j = 0; j <= 79; j += 1) {
95264 T = safe_add(A1, rmd160_f(j, B1, C1, D1));
95265 T = safe_add(T, x[i + rmd160_r1[j]]);
95266 T = safe_add(T, rmd160_K1(j));
95267 T = safe_add(bit_rol(T, rmd160_s1[j]), E1);
95270 D1 = bit_rol(C1, 10);
95273 T = safe_add(A2, rmd160_f(79 - j, B2, C2, D2));
95274 T = safe_add(T, x[i + rmd160_r2[j]]);
95275 T = safe_add(T, rmd160_K2(j));
95276 T = safe_add(bit_rol(T, rmd160_s2[j]), E2);
95279 D2 = bit_rol(C2, 10);
95284 T = safe_add(h1, safe_add(C1, D2));
95285 h1 = safe_add(h2, safe_add(D1, E2));
95286 h2 = safe_add(h3, safe_add(E1, A2));
95287 h3 = safe_add(h4, safe_add(A1, B2));
95288 h4 = safe_add(h0, safe_add(B1, C2));
95292 return [h0, h1, h2, h3, h4];
95293 } // specific algorithm methods
95296 function rmd160_f(j, x, y, z) {
95297 return 0 <= j && j <= 15 ? x ^ y ^ z : 16 <= j && j <= 31 ? x & y | ~x & z : 32 <= j && j <= 47 ? (x | ~y) ^ z : 48 <= j && j <= 63 ? x & z | y & ~z : 64 <= j && j <= 79 ? x ^ (y | ~z) : 'rmd160_f: j out of range';
95300 function rmd160_K1(j) {
95301 return 0 <= j && j <= 15 ? 0x00000000 : 16 <= j && j <= 31 ? 0x5a827999 : 32 <= j && j <= 47 ? 0x6ed9eba1 : 48 <= j && j <= 63 ? 0x8f1bbcdc : 64 <= j && j <= 79 ? 0xa953fd4e : 'rmd160_K1: j out of range';
95304 function rmd160_K2(j) {
95305 return 0 <= j && j <= 15 ? 0x50a28be6 : 16 <= j && j <= 31 ? 0x5c4dd124 : 32 <= j && j <= 47 ? 0x6d703ef3 : 48 <= j && j <= 63 ? 0x7a6d76e9 : 64 <= j && j <= 79 ? 0x00000000 : 'rmd160_K2: j out of range';
95308 }; // exposes Hashes
95310 (function (window, undefined$1) {
95311 var freeExports = false;
95314 freeExports = exports;
95316 if (exports && _typeof(commonjsGlobal) === 'object' && commonjsGlobal && commonjsGlobal === commonjsGlobal.global) {
95317 window = commonjsGlobal;
95321 if (typeof undefined$1 === 'function' && _typeof(undefined$1.amd) === 'object' && undefined$1.amd) {
95322 // define as an anonymous module, so, through path mapping, it can be aliased
95323 undefined$1(function () {
95326 } else if (freeExports) {
95327 // in Node.js or RingoJS v0.8.0+
95328 if (module && module.exports === freeExports) {
95329 module.exports = Hashes;
95330 } // in Narwhal or RingoJS v0.7.0-
95332 freeExports.Hashes = Hashes;
95335 // in a browser or Rhino
95336 window.Hashes = Hashes;
95341 })(hashes$1, hashes$1.exports);
95343 var hashes = hashes$1.exports,
95344 sha1 = new hashes.SHA1(); // # xtend
95346 var hasOwnProperty$1 = Object.prototype.hasOwnProperty;
95348 function xtend$1() {
95351 for (var i = 0; i < arguments.length; i++) {
95352 var source = arguments[i];
95354 for (var key in source) {
95355 if (hasOwnProperty$1.call(source, key)) {
95356 target[key] = source[key];
95366 ohauth$1.qsString = function (obj) {
95367 return Object.keys(obj).sort().map(function (key) {
95368 return ohauth$1.percentEncode(key) + '=' + ohauth$1.percentEncode(obj[key]);
95372 ohauth$1.stringQs = function (str) {
95373 return str.split('&').filter(function (pair) {
95374 return pair !== '';
95375 }).reduce(function (obj, pair) {
95376 var parts = pair.split('=');
95377 obj[decodeURIComponent(parts[0])] = null === parts[1] ? '' : decodeURIComponent(parts[1]);
95382 ohauth$1.rawxhr = function (method, url, data, headers, callback) {
95383 var xhr = new XMLHttpRequest(),
95384 twoHundred = /^20\d$/;
95386 xhr.onreadystatechange = function () {
95387 if (4 === xhr.readyState && 0 !== xhr.status) {
95388 if (twoHundred.test(xhr.status)) callback(null, xhr);else return callback(xhr, null);
95392 xhr.onerror = function (e) {
95393 return callback(e, null);
95396 xhr.open(method, url, true);
95398 for (var h in headers) {
95399 xhr.setRequestHeader(h, headers[h]);
95406 ohauth$1.xhr = function (method, url, auth, data, options, callback) {
95407 var headers = options && options.header || {
95408 'Content-Type': 'application/x-www-form-urlencoded'
95410 headers.Authorization = 'OAuth ' + ohauth$1.authHeader(auth);
95411 return ohauth$1.rawxhr(method, url, data, headers, callback);
95414 ohauth$1.nonce = function () {
95415 for (var o = ''; o.length < 6;) {
95416 o += '0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz'[Math.floor(Math.random() * 61)];
95422 ohauth$1.authHeader = function (obj) {
95423 return Object.keys(obj).sort().map(function (key) {
95424 return encodeURIComponent(key) + '="' + encodeURIComponent(obj[key]) + '"';
95428 ohauth$1.timestamp = function () {
95429 return ~~(+new Date() / 1000);
95432 ohauth$1.percentEncode = function (s) {
95433 return encodeURIComponent(s).replace(/\!/g, '%21').replace(/\'/g, '%27').replace(/\*/g, '%2A').replace(/\(/g, '%28').replace(/\)/g, '%29');
95436 ohauth$1.baseString = function (method, url, params) {
95437 if (params.oauth_signature) delete params.oauth_signature;
95438 return [method, ohauth$1.percentEncode(url), ohauth$1.percentEncode(ohauth$1.qsString(params))].join('&');
95441 ohauth$1.signature = function (oauth_secret, token_secret, baseString) {
95442 return sha1.b64_hmac(ohauth$1.percentEncode(oauth_secret) + '&' + ohauth$1.percentEncode(token_secret), baseString);
95445 * Takes an options object for configuration (consumer_key,
95446 * consumer_secret, version, signature_method, token, token_secret)
95447 * and returns a function that generates the Authorization header
95450 * The returned function takes these parameters:
95451 * - method: GET/POST/...
95452 * - uri: full URI with protocol, port, path and query string
95453 * - extra_params: any extra parameters (that are passed in the POST data),
95454 * can be an object or a from-urlencoded string.
95456 * Returned function returns full OAuth header with "OAuth" string in it.
95460 ohauth$1.headerGenerator = function (options) {
95461 options = options || {};
95462 var consumer_key = options.consumer_key || '',
95463 consumer_secret = options.consumer_secret || '',
95464 signature_method = options.signature_method || 'HMAC-SHA1',
95465 version = options.version || '1.0',
95466 token = options.token || '',
95467 token_secret = options.token_secret || '';
95468 return function (method, uri, extra_params) {
95469 method = method.toUpperCase();
95471 if (typeof extra_params === 'string' && extra_params.length > 0) {
95472 extra_params = ohauth$1.stringQs(extra_params);
95475 var uri_parts = uri.split('?', 2),
95476 base_uri = uri_parts[0];
95477 var query_params = uri_parts.length === 2 ? ohauth$1.stringQs(uri_parts[1]) : {};
95478 var oauth_params = {
95479 oauth_consumer_key: consumer_key,
95480 oauth_signature_method: signature_method,
95481 oauth_version: version,
95482 oauth_timestamp: ohauth$1.timestamp(),
95483 oauth_nonce: ohauth$1.nonce()
95485 if (token) oauth_params.oauth_token = token;
95486 var all_params = xtend$1({}, oauth_params, query_params, extra_params),
95487 base_str = ohauth$1.baseString(method, base_uri, all_params);
95488 oauth_params.oauth_signature = ohauth$1.signature(consumer_secret, token_secret, base_str);
95489 return 'OAuth ' + ohauth$1.authHeader(oauth_params);
95493 var ohauth_1 = ohauth$1;
95495 var resolveUrl$1 = {exports: {}};
95497 (function (module, exports) {
95498 // Copyright 2014 Simon Lydell
95499 // X11 (“MIT”) Licensed. (See LICENSE.)
95500 void function (root, factory) {
95502 module.exports = factory();
95504 }(commonjsGlobal, function () {
95505 function resolveUrl()
95508 var numUrls = arguments.length;
95510 if (numUrls === 0) {
95511 throw new Error("resolveUrl requires at least one argument; got none.");
95514 var base = document.createElement("base");
95515 base.href = arguments[0];
95517 if (numUrls === 1) {
95521 var head = document.getElementsByTagName("head")[0];
95522 head.insertBefore(base, head.firstChild);
95523 var a = document.createElement("a");
95526 for (var index = 1; index < numUrls; index++) {
95527 a.href = arguments[index];
95529 base.href = resolved;
95532 head.removeChild(base);
95540 var assign = make_assign();
95541 var create$1 = make_create();
95542 var trim$1 = make_trim();
95543 var Global$5 = typeof window !== 'undefined' ? window : commonjsGlobal;
95554 isFunction: isFunction$1,
95555 isObject: isObject$1,
95559 function make_assign() {
95560 if (Object.assign) {
95561 return Object.assign;
95563 return function shimAssign(obj, props1, props2, etc) {
95564 for (var i = 1; i < arguments.length; i++) {
95565 each$7(Object(arguments[i]), function (val, key) {
95575 function make_create() {
95576 if (Object.create) {
95577 return function create(obj, assignProps1, assignProps2, etc) {
95578 var assignArgsList = slice$1(arguments, 1);
95579 return assign.apply(this, [Object.create(obj)].concat(assignArgsList));
95582 var F = function F() {}; // eslint-disable-line no-inner-declarations
95585 return function create(obj, assignProps1, assignProps2, etc) {
95586 var assignArgsList = slice$1(arguments, 1);
95588 return assign.apply(this, [new F()].concat(assignArgsList));
95593 function make_trim() {
95594 if (String.prototype.trim) {
95595 return function trim(str) {
95596 return String.prototype.trim.call(str);
95599 return function trim(str) {
95600 return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
95605 function bind$1(obj, fn) {
95606 return function () {
95607 return fn.apply(obj, Array.prototype.slice.call(arguments, 0));
95611 function slice$1(arr, index) {
95612 return Array.prototype.slice.call(arr, index || 0);
95615 function each$7(obj, fn) {
95616 pluck$1(obj, function (val, key) {
95622 function map(obj, fn) {
95623 var res = isList$1(obj) ? [] : {};
95624 pluck$1(obj, function (v, k) {
95631 function pluck$1(obj, fn) {
95632 if (isList$1(obj)) {
95633 for (var i = 0; i < obj.length; i++) {
95634 if (fn(obj[i], i)) {
95639 for (var key in obj) {
95640 if (obj.hasOwnProperty(key)) {
95641 if (fn(obj[key], key)) {
95649 function isList$1(val) {
95650 return val != null && typeof val != 'function' && typeof val.length == 'number';
95653 function isFunction$1(val) {
95654 return val && {}.toString.call(val) === '[object Function]';
95657 function isObject$1(val) {
95658 return val && {}.toString.call(val) === '[object Object]';
95661 var util$5 = util$6;
95662 var slice = util$5.slice;
95663 var pluck = util$5.pluck;
95664 var each$6 = util$5.each;
95665 var bind = util$5.bind;
95666 var create = util$5.create;
95667 var isList = util$5.isList;
95668 var isFunction = util$5.isFunction;
95669 var isObject = util$5.isObject;
95670 var storeEngine = {
95671 createStore: _createStore
95676 // get returns the value of the given key. If that value
95677 // is undefined, it returns optionalDefaultValue instead.
95678 get: function get(key, optionalDefaultValue) {
95679 var data = this.storage.read(this._namespacePrefix + key);
95680 return this._deserialize(data, optionalDefaultValue);
95682 // set will store the given value at key and returns value.
95683 // Calling set with value === undefined is equivalent to calling remove.
95684 set: function set(key, value) {
95685 if (value === undefined) {
95686 return this.remove(key);
95689 this.storage.write(this._namespacePrefix + key, this._serialize(value));
95692 // remove deletes the key and value stored at the given key.
95693 remove: function remove(key) {
95694 this.storage.remove(this._namespacePrefix + key);
95696 // each will call the given callback once for each key-value pair
95698 each: function each(callback) {
95700 this.storage.each(function (val, namespacedKey) {
95701 callback.call(self, self._deserialize(val), (namespacedKey || '').replace(self._namespaceRegexp, ''));
95704 // clearAll will remove all the stored key-value pairs in this store.
95705 clearAll: function clearAll() {
95706 this.storage.clearAll();
95708 // additional functionality that can't live in plugins
95709 // ---------------------------------------------------
95710 // hasNamespace returns true if this store instance has the given namespace.
95711 hasNamespace: function hasNamespace(namespace) {
95712 return this._namespacePrefix == '__storejs_' + namespace + '_';
95714 // createStore creates a store.js instance with the first
95715 // functioning storage in the list of storage candidates,
95716 // and applies the the given mixins to the instance.
95717 createStore: function createStore() {
95718 return _createStore.apply(this, arguments);
95720 addPlugin: function addPlugin(plugin) {
95721 this._addPlugin(plugin);
95723 namespace: function namespace(_namespace) {
95724 return _createStore(this.storage, this.plugins, _namespace);
95729 var _console = typeof console == 'undefined' ? null : console;
95735 var fn = _console.warn ? _console.warn : _console.log;
95736 fn.apply(_console, arguments);
95739 function _createStore(storages, plugins, namespace) {
95744 if (storages && !isList(storages)) {
95745 storages = [storages];
95748 if (plugins && !isList(plugins)) {
95749 plugins = [plugins];
95752 var namespacePrefix = namespace ? '__storejs_' + namespace + '_' : '';
95753 var namespaceRegexp = namespace ? new RegExp('^' + namespacePrefix) : null;
95754 var legalNamespaces = /^[a-zA-Z0-9_\-]*$/; // alpha-numeric + underscore and dash
95756 if (!legalNamespaces.test(namespace)) {
95757 throw new Error('store.js namespaces can only have alphanumerics + underscores and dashes');
95760 var _privateStoreProps = {
95761 _namespacePrefix: namespacePrefix,
95762 _namespaceRegexp: namespaceRegexp,
95763 _testStorage: function _testStorage(storage) {
95765 var testStr = '__storejs__test__';
95766 storage.write(testStr, testStr);
95767 var ok = storage.read(testStr) === testStr;
95768 storage.remove(testStr);
95774 _assignPluginFnProp: function _assignPluginFnProp(pluginFnProp, propName) {
95775 var oldFn = this[propName];
95777 this[propName] = function pluginFn() {
95778 var args = slice(arguments, 0);
95779 var self = this; // super_fn calls the old function which was overwritten by
95782 function super_fn() {
95787 each$6(arguments, function (arg, i) {
95790 return oldFn.apply(self, args);
95791 } // Give mixing function access to super_fn by prefixing all mixin function
95792 // arguments with super_fn.
95795 var newFnArgs = [super_fn].concat(args);
95796 return pluginFnProp.apply(self, newFnArgs);
95799 _serialize: function _serialize(obj) {
95800 return JSON.stringify(obj);
95802 _deserialize: function _deserialize(strVal, defaultVal) {
95805 } // It is possible that a raw string value has been previously stored
95806 // in a storage without using store.js, meaning it will be a raw
95807 // string value instead of a JSON serialized string. By defaulting
95808 // to the raw string value in case of a JSON parse error, we allow
95809 // for past stored values to be forwards-compatible with store.js
95815 val = JSON.parse(strVal);
95820 return val !== undefined ? val : defaultVal;
95822 _addStorage: function _addStorage(storage) {
95823 if (this.enabled) {
95827 if (this._testStorage(storage)) {
95828 this.storage = storage;
95829 this.enabled = true;
95832 _addPlugin: function _addPlugin(plugin) {
95833 var self = this; // If the plugin is an array, then add all plugins in the array.
95834 // This allows for a plugin to depend on other plugins.
95836 if (isList(plugin)) {
95837 each$6(plugin, function (plugin) {
95838 self._addPlugin(plugin);
95841 } // Keep track of all plugins we've seen so far, so that we
95842 // don't add any of them twice.
95845 var seenPlugin = pluck(this.plugins, function (seenPlugin) {
95846 return plugin === seenPlugin;
95853 this.plugins.push(plugin); // Check that the plugin is properly formed
95855 if (!isFunction(plugin)) {
95856 throw new Error('Plugins must be function values that return objects');
95859 var pluginProperties = plugin.call(this);
95861 if (!isObject(pluginProperties)) {
95862 throw new Error('Plugins must return an object of function properties');
95863 } // Add the plugin function properties to this store instance.
95866 each$6(pluginProperties, function (pluginFnProp, propName) {
95867 if (!isFunction(pluginFnProp)) {
95868 throw new Error('Bad plugin property: ' + propName + ' from plugin ' + plugin.name + '. Plugins should only return functions.');
95871 self._assignPluginFnProp(pluginFnProp, propName);
95874 // Put deprecated properties in the private API, so as to not expose it to accidential
95875 // discovery through inspection of the store object.
95876 // Deprecated: addStorage
95877 addStorage: function addStorage(storage) {
95878 _warn('store.addStorage(storage) is deprecated. Use createStore([storages])');
95880 this._addStorage(storage);
95883 var store = create(_privateStoreProps, storeAPI, {
95887 each$6(store, function (prop, propName) {
95888 if (isFunction(prop)) {
95889 store.raw[propName] = bind(store, prop);
95892 each$6(storages, function (storage) {
95893 store._addStorage(storage);
95895 each$6(plugins, function (plugin) {
95896 store._addPlugin(plugin);
95901 var util$4 = util$6;
95902 var Global$4 = util$4.Global;
95903 var localStorage_1 = {
95904 name: 'localStorage',
95909 clearAll: clearAll$5
95912 function localStorage$1() {
95913 return Global$4.localStorage;
95916 function read$5(key) {
95917 return localStorage$1().getItem(key);
95920 function write$5(key, data) {
95921 return localStorage$1().setItem(key, data);
95924 function each$5(fn) {
95925 for (var i = localStorage$1().length - 1; i >= 0; i--) {
95926 var key = localStorage$1().key(i);
95927 fn(read$5(key), key);
95931 function remove$5(key) {
95932 return localStorage$1().removeItem(key);
95935 function clearAll$5() {
95936 return localStorage$1().clear();
95939 // versions 6 and 7, where no localStorage, etc
95942 var util$3 = util$6;
95943 var Global$3 = util$3.Global;
95944 var oldFFGlobalStorage = {
95945 name: 'oldFF-globalStorage',
95950 clearAll: clearAll$4
95952 var globalStorage = Global$3.globalStorage;
95954 function read$4(key) {
95955 return globalStorage[key];
95958 function write$4(key, data) {
95959 globalStorage[key] = data;
95962 function each$4(fn) {
95963 for (var i = globalStorage.length - 1; i >= 0; i--) {
95964 var key = globalStorage.key(i);
95965 fn(globalStorage[key], key);
95969 function remove$4(key) {
95970 return globalStorage.removeItem(key);
95973 function clearAll$4() {
95974 each$4(function (key, _) {
95975 delete globalStorage[key];
95979 // versions 6 and 7, where no localStorage, sessionStorage, etc
95982 var util$2 = util$6;
95983 var Global$2 = util$2.Global;
95984 var oldIEUserDataStorage = {
95985 name: 'oldIE-userDataStorage',
95990 clearAll: clearAll$3
95992 var storageName = 'storejs';
95993 var doc$1 = Global$2.document;
95995 var _withStorageEl = _makeIEStorageElFunction();
95997 var disable = (Global$2.navigator ? Global$2.navigator.userAgent : '').match(/ (MSIE 8|MSIE 9|MSIE 10)\./); // MSIE 9.x, MSIE 10.x
95999 function write$3(unfixedKey, data) {
96004 var fixedKey = fixKey(unfixedKey);
96006 _withStorageEl(function (storageEl) {
96007 storageEl.setAttribute(fixedKey, data);
96008 storageEl.save(storageName);
96012 function read$3(unfixedKey) {
96017 var fixedKey = fixKey(unfixedKey);
96020 _withStorageEl(function (storageEl) {
96021 res = storageEl.getAttribute(fixedKey);
96027 function each$3(callback) {
96028 _withStorageEl(function (storageEl) {
96029 var attributes = storageEl.XMLDocument.documentElement.attributes;
96031 for (var i = attributes.length - 1; i >= 0; i--) {
96032 var attr = attributes[i];
96033 callback(storageEl.getAttribute(attr.name), attr.name);
96038 function remove$3(unfixedKey) {
96039 var fixedKey = fixKey(unfixedKey);
96041 _withStorageEl(function (storageEl) {
96042 storageEl.removeAttribute(fixedKey);
96043 storageEl.save(storageName);
96047 function clearAll$3() {
96048 _withStorageEl(function (storageEl) {
96049 var attributes = storageEl.XMLDocument.documentElement.attributes;
96050 storageEl.load(storageName);
96052 for (var i = attributes.length - 1; i >= 0; i--) {
96053 storageEl.removeAttribute(attributes[i].name);
96056 storageEl.save(storageName);
96060 // In IE7, keys cannot start with a digit or contain certain chars.
96061 // See https://github.com/marcuswestin/store.js/issues/40
96062 // See https://github.com/marcuswestin/store.js/issues/83
96065 var forbiddenCharsRegex = new RegExp("[!\"#$%&'()*+,/\\\\:;<=>?@[\\]^`{|}~]", "g");
96067 function fixKey(key) {
96068 return key.replace(/^\d/, '___$&').replace(forbiddenCharsRegex, '___');
96071 function _makeIEStorageElFunction() {
96072 if (!doc$1 || !doc$1.documentElement || !doc$1.documentElement.addBehavior) {
96076 var scriptTag = 'script',
96079 storageEl; // Since #userData storage applies only to specific paths, we need to
96080 // somehow link our data to a specific path. We choose /favicon.ico
96081 // as a pretty safe option, since all browsers already make a request to
96082 // this URL anyway and being a 404 will not hurt us here. We wrap an
96083 // iframe pointing to the favicon in an ActiveXObject(htmlfile) object
96084 // (see: http://msdn.microsoft.com/en-us/library/aa752574(v=VS.85).aspx)
96085 // since the iframe access rules appear to allow direct access and
96086 // manipulation of the document element, even for a 404 page. This
96087 // document can be used instead of the current document (which would
96088 // have been limited to the current path) to perform #userData storage.
96091 /* global ActiveXObject */
96092 storageContainer = new ActiveXObject('htmlfile');
96093 storageContainer.open();
96094 storageContainer.write('<' + scriptTag + '>document.w=window</' + scriptTag + '><iframe src="/favicon.ico"></iframe>');
96095 storageContainer.close();
96096 storageOwner = storageContainer.w.frames[0].document;
96097 storageEl = storageOwner.createElement('div');
96099 // somehow ActiveXObject instantiation failed (perhaps some special
96100 // security settings or otherwse), fall back to per-path storage
96101 storageEl = doc$1.createElement('div');
96102 storageOwner = doc$1.body;
96105 return function (storeFunction) {
96106 var args = [].slice.call(arguments, 0);
96107 args.unshift(storageEl); // See http://msdn.microsoft.com/en-us/library/ms531081(v=VS.85).aspx
96108 // and http://msdn.microsoft.com/en-us/library/ms531424(v=VS.85).aspx
96110 storageOwner.appendChild(storageEl);
96111 storageEl.addBehavior('#default#userData');
96112 storageEl.load(storageName);
96113 storeFunction.apply(this, args);
96114 storageOwner.removeChild(storageEl);
96119 // doesn't work but cookies do. This implementation is adopted from
96120 // https://developer.mozilla.org/en-US/docs/Web/API/Storage/LocalStorage
96122 var util$1 = util$6;
96123 var Global$1 = util$1.Global;
96124 var trim = util$1.trim;
96125 var cookieStorage = {
96126 name: 'cookieStorage',
96131 clearAll: clearAll$2
96133 var doc = Global$1.document;
96135 function read$2(key) {
96136 if (!key || !_has(key)) {
96140 var regexpStr = "(?:^|.*;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=\\s*((?:[^;](?!;))*[^;]?).*";
96141 return unescape(doc.cookie.replace(new RegExp(regexpStr), "$1"));
96144 function each$2(callback) {
96145 var cookies = doc.cookie.split(/; ?/g);
96147 for (var i = cookies.length - 1; i >= 0; i--) {
96148 if (!trim(cookies[i])) {
96152 var kvp = cookies[i].split('=');
96153 var key = unescape(kvp[0]);
96154 var val = unescape(kvp[1]);
96155 callback(val, key);
96159 function write$2(key, data) {
96164 doc.cookie = escape(key) + "=" + escape(data) + "; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";
96167 function remove$2(key) {
96168 if (!key || !_has(key)) {
96172 doc.cookie = escape(key) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/";
96175 function clearAll$2() {
96176 each$2(function (_, key) {
96181 function _has(key) {
96182 return new RegExp("(?:^|;\\s*)" + escape(key).replace(/[\-\.\+\*]/g, "\\$&") + "\\s*\\=").test(doc.cookie);
96186 var Global = util.Global;
96187 var sessionStorage_1 = {
96188 name: 'sessionStorage',
96193 clearAll: clearAll$1
96196 function sessionStorage() {
96197 return Global.sessionStorage;
96200 function read$1(key) {
96201 return sessionStorage().getItem(key);
96204 function write$1(key, data) {
96205 return sessionStorage().setItem(key, data);
96208 function each$1(fn) {
96209 for (var i = sessionStorage().length - 1; i >= 0; i--) {
96210 var key = sessionStorage().key(i);
96211 fn(read$1(key), key);
96215 function remove$1(key) {
96216 return sessionStorage().removeItem(key);
96219 function clearAll$1() {
96220 return sessionStorage().clear();
96223 // is functions (meaning store.get(), store.set(), etc will all function).
96224 // However, stored values will not persist when the browser navigates to
96225 // a new page or reloads the current page.
96227 var memoryStorage_1 = {
96228 name: 'memoryStorage',
96235 var memoryStorage = {};
96237 function read(key) {
96238 return memoryStorage[key];
96241 function write(key, data) {
96242 memoryStorage[key] = data;
96245 function each(callback) {
96246 for (var key in memoryStorage) {
96247 if (memoryStorage.hasOwnProperty(key)) {
96248 callback(memoryStorage[key], key);
96253 function remove(key) {
96254 delete memoryStorage[key];
96257 function clearAll(key) {
96258 memoryStorage = {};
96261 var all = [// Listed in order of usage preference
96262 localStorage_1, oldFFGlobalStorage, oldIEUserDataStorage, cookieStorage, sessionStorage_1, memoryStorage_1];
96264 /* eslint-disable */
96268 // NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
96269 // See http://www.JSON.org/js.html
96270 // This code should be minified before deployment.
96271 // See http://javascript.crockford.com/jsmin.html
96272 // USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
96274 // This file creates a global JSON object containing two methods: stringify
96275 // and parse. This file provides the ES5 JSON capability to ES3 systems.
96276 // If a project might run on IE8 or earlier, then this file should be included.
96277 // This file does nothing on ES5 systems.
96278 // JSON.stringify(value, replacer, space)
96279 // value any JavaScript value, usually an object or array.
96280 // replacer an optional parameter that determines how object
96281 // values are stringified for objects. It can be a
96282 // function or an array of strings.
96283 // space an optional parameter that specifies the indentation
96284 // of nested structures. If it is omitted, the text will
96285 // be packed without extra whitespace. If it is a number,
96286 // it will specify the number of spaces to indent at each
96287 // level. If it is a string (such as "\t" or " "),
96288 // it contains the characters used to indent at each level.
96289 // This method produces a JSON text from a JavaScript value.
96290 // When an object value is found, if the object contains a toJSON
96291 // method, its toJSON method will be called and the result will be
96292 // stringified. A toJSON method does not serialize: it returns the
96293 // value represented by the name/value pair that should be serialized,
96294 // or undefined if nothing should be serialized. The toJSON method
96295 // will be passed the key associated with the value, and this will be
96296 // bound to the value.
96297 // For example, this would serialize Dates as ISO strings.
96298 // Date.prototype.toJSON = function (key) {
96300 // // Format integers to have at least two digits.
96305 // return this.getUTCFullYear() + "-" +
96306 // f(this.getUTCMonth() + 1) + "-" +
96307 // f(this.getUTCDate()) + "T" +
96308 // f(this.getUTCHours()) + ":" +
96309 // f(this.getUTCMinutes()) + ":" +
96310 // f(this.getUTCSeconds()) + "Z";
96312 // You can provide an optional replacer method. It will be passed the
96313 // key and value of each member, with this bound to the containing
96314 // object. The value that is returned from your method will be
96315 // serialized. If your method returns undefined, then the member will
96316 // be excluded from the serialization.
96317 // If the replacer parameter is an array of strings, then it will be
96318 // used to select the members to be serialized. It filters the results
96319 // such that only members with keys listed in the replacer array are
96321 // Values that do not have JSON representations, such as undefined or
96322 // functions, will not be serialized. Such values in objects will be
96323 // dropped; in arrays they will be replaced with null. You can use
96324 // a replacer function to replace those with JSON values.
96325 // JSON.stringify(undefined) returns undefined.
96326 // The optional space parameter produces a stringification of the
96327 // value that is filled with line breaks and indentation to make it
96329 // If the space parameter is a non-empty string, then that string will
96330 // be used for indentation. If the space parameter is a number, then
96331 // the indentation will be that many spaces.
96333 // text = JSON.stringify(["e", {pluribus: "unum"}]);
96334 // // text is '["e",{"pluribus":"unum"}]'
96335 // text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
96336 // // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
96337 // text = JSON.stringify([new Date()], function (key, value) {
96338 // return this[key] instanceof Date
96339 // ? "Date(" + this[key] + ")"
96342 // // text is '["Date(---current time---)"]'
96343 // JSON.parse(text, reviver)
96344 // This method parses a JSON text to produce an object or array.
96345 // It can throw a SyntaxError exception.
96346 // The optional reviver parameter is a function that can filter and
96347 // transform the results. It receives each of the keys and values,
96348 // and its return value is used instead of the original value.
96349 // If it returns what it received, then the structure is not modified.
96350 // If it returns undefined then the member is deleted.
96352 // // Parse the text. Values that look like ISO date strings will
96353 // // be converted to Date objects.
96354 // myData = JSON.parse(text, function (key, value) {
96356 // if (typeof value === "string") {
96358 // /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
96360 // return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
96366 // myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
96368 // if (typeof value === "string" &&
96369 // value.slice(0, 5) === "Date(" &&
96370 // value.slice(-1) === ")") {
96371 // d = new Date(value.slice(5, -1));
96378 // This is a reference implementation. You are free to copy, modify, or
96386 JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
96387 getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
96388 lastIndex, length, parse, prototype, push, replace, slice, stringify,
96389 test, toJSON, toString, valueOf
96391 // Create a JSON object only if one does not already exist. We create the
96392 // methods in a closure to avoid creating global variables.
96393 if ((typeof JSON === "undefined" ? "undefined" : _typeof(JSON)) !== "object") {
96399 var rx_one = /^[\],:{}\s]*$/;
96400 var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
96401 var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
96402 var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
96403 var rx_escapable = /[\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
96404 var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
96407 // Format integers to have at least two digits.
96408 return n < 10 ? "0" + n : n;
96411 function this_value() {
96412 return this.valueOf();
96415 if (typeof Date.prototype.toJSON !== "function") {
96416 Date.prototype.toJSON = function () {
96417 return isFinite(this.valueOf()) ? this.getUTCFullYear() + "-" + f(this.getUTCMonth() + 1) + "-" + f(this.getUTCDate()) + "T" + f(this.getUTCHours()) + ":" + f(this.getUTCMinutes()) + ":" + f(this.getUTCSeconds()) + "Z" : null;
96420 Boolean.prototype.toJSON = this_value;
96421 Number.prototype.toJSON = this_value;
96422 String.prototype.toJSON = this_value;
96430 function quote(string) {
96431 // If the string contains no control characters, no quote characters, and no
96432 // backslash characters, then we can safely slap some quotes around it.
96433 // Otherwise we must also replace the offending characters with safe escape
96435 rx_escapable.lastIndex = 0;
96436 return rx_escapable.test(string) ? "\"" + string.replace(rx_escapable, function (a) {
96438 return typeof c === "string" ? c : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
96439 }) + "\"" : "\"" + string + "\"";
96442 function str(key, holder) {
96443 // Produce a string from holder[key].
96444 var i; // The loop counter.
96446 var k; // The member key.
96448 var v; // The member value.
96453 var value = holder[key]; // If the value has a toJSON method, call it to obtain a replacement value.
96455 if (value && _typeof(value) === "object" && typeof value.toJSON === "function") {
96456 value = value.toJSON(key);
96457 } // If we were called with a replacer function, then call the replacer to
96458 // obtain a replacement value.
96461 if (typeof rep === "function") {
96462 value = rep.call(holder, key, value);
96463 } // What happens next depends on the value's type.
96466 switch (_typeof(value)) {
96468 return quote(value);
96471 // JSON numbers must be finite. Encode non-finite numbers as null.
96472 return isFinite(value) ? String(value) : "null";
96476 // If the value is a boolean or null, convert it to a string. Note:
96477 // typeof null does not produce "null". The case is included here in
96478 // the remote chance that this gets fixed someday.
96479 return String(value);
96480 // If the type is "object", we might be dealing with an object or an array or
96484 // Due to a specification blunder in ECMAScript, typeof null is "object",
96485 // so watch out for that case.
96488 } // Make an array to hold the partial results of stringifying this object value.
96492 partial = []; // Is the value an array?
96494 if (Object.prototype.toString.apply(value) === "[object Array]") {
96495 // The value is an array. Stringify every element. Use null as a placeholder
96496 // for non-JSON values.
96497 length = value.length;
96499 for (i = 0; i < length; i += 1) {
96500 partial[i] = str(i, value) || "null";
96501 } // Join all of the elements together, separated with commas, and wrap them in
96505 v = partial.length === 0 ? "[]" : gap ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]" : "[" + partial.join(",") + "]";
96508 } // If the replacer is an array, use it to select the members to be stringified.
96511 if (rep && _typeof(rep) === "object") {
96512 length = rep.length;
96514 for (i = 0; i < length; i += 1) {
96515 if (typeof rep[i] === "string") {
96520 partial.push(quote(k) + (gap ? ": " : ":") + v);
96525 // Otherwise, iterate through all of the keys in the object.
96527 if (Object.prototype.hasOwnProperty.call(value, k)) {
96531 partial.push(quote(k) + (gap ? ": " : ":") + v);
96535 } // Join all of the member texts together, separated with commas,
96536 // and wrap them in braces.
96539 v = partial.length === 0 ? "{}" : gap ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}" : "{" + partial.join(",") + "}";
96543 } // If the JSON object does not yet have a stringify method, give it one.
96546 if (typeof JSON.stringify !== "function") {
96548 // table of character substitutions
96558 JSON.stringify = function (value, replacer, space) {
96559 // The stringify method takes a value and an optional replacer, and an optional
96560 // space parameter, and returns a JSON text. The replacer can be a function
96561 // that can replace values, or an array of strings that will select the keys.
96562 // A default replacer method can be provided. Use of the space parameter can
96563 // produce text that is more easily readable.
96566 indent = ""; // If the space parameter is a number, make an indent string containing that
96569 if (typeof space === "number") {
96570 for (i = 0; i < space; i += 1) {
96572 } // If the space parameter is a string, it will be used as the indent string.
96574 } else if (typeof space === "string") {
96576 } // If there is a replacer, it must be a function or an array.
96577 // Otherwise, throw an error.
96582 if (replacer && typeof replacer !== "function" && (_typeof(replacer) !== "object" || typeof replacer.length !== "number")) {
96583 throw new Error("JSON.stringify");
96584 } // Make a fake root object containing our value under the key of "".
96585 // Return the result of stringifying the value.
96592 } // If the JSON object does not yet have a parse method, give it one.
96595 if (typeof JSON.parse !== "function") {
96596 JSON.parse = function (text, reviver) {
96597 // The parse method takes a text and an optional reviver function, and returns
96598 // a JavaScript value if the text is a valid JSON text.
96601 function walk(holder, key) {
96602 // The walk method is used to recursively walk the resulting structure so
96603 // that modifications can be made.
96606 var value = holder[key];
96608 if (value && _typeof(value) === "object") {
96610 if (Object.prototype.hasOwnProperty.call(value, k)) {
96611 v = walk(value, k);
96613 if (v !== undefined) {
96622 return reviver.call(holder, key, value);
96623 } // Parsing happens in four stages. In the first stage, we replace certain
96624 // Unicode characters with escape sequences. JavaScript handles many characters
96625 // incorrectly, either silently deleting them, or treating them as line endings.
96628 text = String(text);
96629 rx_dangerous.lastIndex = 0;
96631 if (rx_dangerous.test(text)) {
96632 text = text.replace(rx_dangerous, function (a) {
96633 return "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
96635 } // In the second stage, we run the text against regular expressions that look
96636 // for non-JSON patterns. We are especially concerned with "()" and "new"
96637 // because they can cause invocation, and "=" because it can cause mutation.
96638 // But just to be safe, we want to reject all unexpected forms.
96639 // We split the second stage into 4 regexp operations in order to work around
96640 // crippling inefficiencies in IE's and Safari's regexp engines. First we
96641 // replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
96642 // replace all simple value tokens with "]" characters. Third, we delete all
96643 // open brackets that follow a colon or comma or that begin the text. Finally,
96644 // we look to see that the remaining characters are only whitespace or "]" or
96645 // "," or ":" or "{" or "}". If that is so, then the text is safe for eval.
96648 if (rx_one.test(text.replace(rx_two, "@").replace(rx_three, "]").replace(rx_four, ""))) {
96649 // In the third stage we use the eval function to compile the text into a
96650 // JavaScript structure. The "{" operator is subject to a syntactic ambiguity
96651 // in JavaScript: it can begin a block or an object literal. We wrap the text
96652 // in parens to eliminate the ambiguity.
96653 j = eval("(" + text + ")"); // In the optional fourth stage, we recursively walk the new structure, passing
96654 // each name/value pair to a reviver function for possible transformation.
96656 return typeof reviver === "function" ? walk({
96659 } // If the text is not JSON parseable, then a SyntaxError is thrown.
96662 throw new SyntaxError("JSON.parse");
96667 var json2 = json2Plugin;
96669 function json2Plugin() {
96673 var engine = storeEngine;
96674 var storages = all;
96675 var plugins = [json2];
96676 var store_legacy = engine.createStore(storages, plugins);
96678 var immutable = extend;
96679 var hasOwnProperty = Object.prototype.hasOwnProperty;
96681 function extend() {
96684 for (var i = 0; i < arguments.length; i++) {
96685 var source = arguments[i];
96687 for (var key in source) {
96688 if (hasOwnProperty.call(source, key)) {
96689 target[key] = source[key];
96697 var ohauth = ohauth_1;
96698 var resolveUrl = resolveUrl$1.exports;
96699 var store = store_legacy;
96700 var xtend = immutable; // # osm-auth
96702 // This code is only compatible with IE10+ because the [XDomainRequest](http://bit.ly/LfO7xo)
96703 // object, IE<10's idea of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing),
96704 // does not support custom headers, which this uses everywhere.
96706 var osmAuth = function osmAuth(o) {
96707 var oauth = {}; // authenticated users will also have a request token secret, but it's
96708 // not used in transactions with the server
96710 oauth.authenticated = function () {
96711 return !!(token('oauth_token') && token('oauth_token_secret'));
96714 oauth.logout = function () {
96715 token('oauth_token', '');
96716 token('oauth_token_secret', '');
96717 token('oauth_request_token_secret', '');
96719 }; // TODO: detect lack of click event
96722 oauth.authenticate = function (callback) {
96723 if (oauth.authenticated()) return callback();
96724 oauth.logout(); // ## Getting a request token
96726 var params = timenonce(getAuth(o)),
96727 url = o.url + '/oauth/request_token';
96728 params.oauth_signature = ohauth.signature(o.oauth_secret, '', ohauth.baseString('POST', url, params));
96730 if (!o.singlepage) {
96731 // Create a 600x550 popup window in the center of the screen
96734 settings = [['width', w], ['height', h], ['left', screen.width / 2 - w / 2], ['top', screen.height / 2 - h / 2]].map(function (x) {
96735 return x.join('=');
96737 popup = window.open('about:blank', 'oauth_window', settings);
96738 oauth.popupWindow = popup;
96741 var error = new Error('Popup was blocked');
96742 error.status = 'popup-blocked';
96745 } // Request a request token. When this is complete, the popup
96746 // window is redirected to OSM's authorization page.
96749 ohauth.xhr('POST', url, params, null, {}, reqTokenDone);
96752 function reqTokenDone(err, xhr) {
96754 if (err) return callback(err);
96755 var resp = ohauth.stringQs(xhr.response);
96756 token('oauth_request_token_secret', resp.oauth_token_secret);
96757 var authorize_url = o.url + '/oauth/authorize?' + ohauth.qsString({
96758 oauth_token: resp.oauth_token,
96759 oauth_callback: resolveUrl(o.landing)
96762 if (o.singlepage) {
96763 location.href = authorize_url;
96765 popup.location = authorize_url;
96767 } // Called by a function in a landing page, in the popup window. The
96768 // window closes itself.
96771 window.authComplete = function (token) {
96772 var oauth_token = ohauth.stringQs(token.split('?')[1]);
96773 get_access_token(oauth_token.oauth_token);
96774 delete window.authComplete;
96775 }; // ## Getting an request token
96777 // At this point we have an `oauth_token`, brought in from a function
96778 // call on a landing page popup.
96781 function get_access_token(oauth_token) {
96782 var url = o.url + '/oauth/access_token',
96783 params = timenonce(getAuth(o)),
96784 request_token_secret = token('oauth_request_token_secret');
96785 params.oauth_token = oauth_token;
96786 params.oauth_signature = ohauth.signature(o.oauth_secret, request_token_secret, ohauth.baseString('POST', url, params)); // ## Getting an access token
96788 // The final token required for authentication. At this point
96789 // we have a `request token secret`
96791 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
96795 function accessTokenDone(err, xhr) {
96797 if (err) return callback(err);
96798 var access_token = ohauth.stringQs(xhr.response);
96799 token('oauth_token', access_token.oauth_token);
96800 token('oauth_token_secret', access_token.oauth_token_secret);
96801 callback(null, oauth);
96805 oauth.bringPopupWindowToFront = function () {
96806 var brougtPopupToFront = false;
96809 // This may cause a cross-origin error:
96810 // `DOMException: Blocked a frame with origin "..." from accessing a cross-origin frame.`
96811 if (oauth.popupWindow && !oauth.popupWindow.closed) {
96812 oauth.popupWindow.focus();
96813 brougtPopupToFront = true;
96815 } catch (err) {// Bringing popup window to front failed (probably because of the cross-origin error mentioned above)
96818 return brougtPopupToFront;
96821 oauth.bootstrapToken = function (oauth_token, callback) {
96822 // ## Getting an request token
96823 // At this point we have an `oauth_token`, brought in from a function
96824 // call on a landing page popup.
96825 function get_access_token(oauth_token) {
96826 var url = o.url + '/oauth/access_token',
96827 params = timenonce(getAuth(o)),
96828 request_token_secret = token('oauth_request_token_secret');
96829 params.oauth_token = oauth_token;
96830 params.oauth_signature = ohauth.signature(o.oauth_secret, request_token_secret, ohauth.baseString('POST', url, params)); // ## Getting an access token
96831 // The final token required for authentication. At this point
96832 // we have a `request token secret`
96834 ohauth.xhr('POST', url, params, null, {}, accessTokenDone);
96838 function accessTokenDone(err, xhr) {
96840 if (err) return callback(err);
96841 var access_token = ohauth.stringQs(xhr.response);
96842 token('oauth_token', access_token.oauth_token);
96843 token('oauth_token_secret', access_token.oauth_token_secret);
96844 callback(null, oauth);
96847 get_access_token(oauth_token);
96850 // A single XMLHttpRequest wrapper that does authenticated calls if the
96851 // user has logged in.
96854 oauth.xhr = function (options, callback) {
96855 if (!oauth.authenticated()) {
96857 return oauth.authenticate(run);
96859 callback('not authenticated', null);
96867 var params = timenonce(getAuth(o)),
96868 oauth_token_secret = token('oauth_token_secret'),
96869 url = options.prefix !== false ? o.url + options.path : options.path,
96870 url_parts = url.replace(/#.*$/, '').split('?', 2),
96871 base_url = url_parts[0],
96872 query = url_parts.length === 2 ? url_parts[1] : ''; // https://tools.ietf.org/html/rfc5849#section-3.4.1.3.1
96874 if ((!options.options || !options.options.header || options.options.header['Content-Type'] === 'application/x-www-form-urlencoded') && options.content) {
96875 params = xtend(params, ohauth.stringQs(options.content));
96878 params.oauth_token = token('oauth_token');
96879 params.oauth_signature = ohauth.signature(o.oauth_secret, oauth_token_secret, ohauth.baseString(options.method, base_url, xtend(params, ohauth.stringQs(query))));
96880 return ohauth.xhr(options.method, url, params, options.content, options.options, done);
96883 function done(err, xhr) {
96884 if (err) return callback(err);else if (xhr.responseXML) return callback(err, xhr.responseXML);else return callback(err, xhr.response);
96886 }; // pre-authorize this object, if we can just get a token and token_secret
96890 oauth.preauth = function (c) {
96892 if (c.oauth_token) token('oauth_token', c.oauth_token);
96893 if (c.oauth_token_secret) token('oauth_token_secret', c.oauth_token_secret);
96897 oauth.options = function (_) {
96898 if (!arguments.length) return o;
96900 o.url = o.url || 'https://www.openstreetmap.org';
96901 o.landing = o.landing || 'land.html';
96902 o.singlepage = o.singlepage || false; // Optional loading and loading-done functions for nice UI feedback.
96903 // by default, no-ops
96905 o.loading = o.loading || function () {};
96907 o.done = o.done || function () {};
96909 return oauth.preauth(o);
96910 }; // 'stamp' an authentication object from `getAuth()`
96911 // with a [nonce](http://en.wikipedia.org/wiki/Cryptographic_nonce)
96915 function timenonce(o) {
96916 o.oauth_timestamp = ohauth.timestamp();
96917 o.oauth_nonce = ohauth.nonce();
96919 } // get/set tokens. These are prefixed with the base URL so that `osm-auth`
96920 // can be used with multiple APIs and the keys in `localStorage`
96926 if (store.enabled) {
96927 token = function token(x, y) {
96928 if (arguments.length === 1) return store.get(o.url + x);else if (arguments.length === 2) return store.set(o.url + x, y);
96933 token = function token(x, y) {
96934 if (arguments.length === 1) return storage[o.url + x];else if (arguments.length === 2) return storage[o.url + x] = y;
96936 } // Get an authentication object. If you just add and remove properties
96937 // from a single object, you'll need to use `delete` to make sure that
96938 // it doesn't contain undesired properties for authentication
96941 function getAuth(o) {
96943 oauth_consumer_key: o.oauth_consumer_key,
96944 oauth_signature_method: 'HMAC-SHA1'
96946 } // potentially pre-authorize
96953 var tiler$2 = utilTiler();
96954 var dispatch$2 = dispatch$8('apiStatusChange', 'authLoading', 'authDone', 'change', 'loading', 'loaded', 'loadedNotes');
96955 var urlroot = 'https://www.openstreetmap.org';
96956 var oauth = osmAuth({
96958 oauth_consumer_key: '5A043yRSEugj4DJ5TljuapfnrflWDte8jTOcWLlT',
96959 oauth_secret: 'aB3jKq1TRsCOUrfOIZ6oQMEDmv2ptV76PA54NGLL',
96960 loading: authLoading,
96962 }); // hardcode default block of Google Maps
96964 var _imageryBlocklists = [/.*\.google(apis)?\..*\/(vt|kh)[\?\/].*([xyz]=.*){3}.*/];
96986 var _cachedApiStatus;
96988 var _changeset = {};
96990 var _deferred = new Set();
96992 var _connectionID = 1;
96993 var _tileZoom = 16;
96994 var _noteZoom = 12;
96996 var _rateLimitError;
96998 var _userChangesets;
97002 var _off; // set a default but also load this from the API status
97005 var _maxWayNodes = 2000;
97007 function authLoading() {
97008 dispatch$2.call('authLoading');
97011 function authDone() {
97012 dispatch$2.call('authDone');
97015 function abortRequest$2(controllerOrXHR) {
97016 if (controllerOrXHR) {
97017 controllerOrXHR.abort();
97021 function hasInflightRequests(cache) {
97022 return Object.keys(cache.inflight).length;
97025 function abortUnwantedRequests(cache, visibleTiles) {
97026 Object.keys(cache.inflight).forEach(function (k) {
97027 if (cache.toLoad[k]) return;
97028 if (visibleTiles.find(function (tile) {
97029 return k === tile.id;
97031 abortRequest$2(cache.inflight[k]);
97032 delete cache.inflight[k];
97036 function getLoc(attrs) {
97037 var lon = attrs.lon && attrs.lon.value;
97038 var lat = attrs.lat && attrs.lat.value;
97039 return [parseFloat(lon), parseFloat(lat)];
97042 function getNodes(obj) {
97043 var elems = obj.getElementsByTagName('nd');
97044 var nodes = new Array(elems.length);
97046 for (var i = 0, l = elems.length; i < l; i++) {
97047 nodes[i] = 'n' + elems[i].attributes.ref.value;
97053 function getNodesJSON(obj) {
97054 var elems = obj.nodes;
97055 var nodes = new Array(elems.length);
97057 for (var i = 0, l = elems.length; i < l; i++) {
97058 nodes[i] = 'n' + elems[i];
97064 function getTags(obj) {
97065 var elems = obj.getElementsByTagName('tag');
97068 for (var i = 0, l = elems.length; i < l; i++) {
97069 var attrs = elems[i].attributes;
97070 tags[attrs.k.value] = attrs.v.value;
97076 function getMembers(obj) {
97077 var elems = obj.getElementsByTagName('member');
97078 var members = new Array(elems.length);
97080 for (var i = 0, l = elems.length; i < l; i++) {
97081 var attrs = elems[i].attributes;
97083 id: attrs.type.value[0] + attrs.ref.value,
97084 type: attrs.type.value,
97085 role: attrs.role.value
97092 function getMembersJSON(obj) {
97093 var elems = obj.members;
97094 var members = new Array(elems.length);
97096 for (var i = 0, l = elems.length; i < l; i++) {
97097 var attrs = elems[i];
97099 id: attrs.type[0] + attrs.ref,
97108 function getVisible(attrs) {
97109 return !attrs.visible || attrs.visible.value !== 'false';
97112 function parseComments(comments) {
97113 var parsedComments = []; // for each comment
97115 for (var i = 0; i < comments.length; i++) {
97116 var comment = comments[i];
97118 if (comment.nodeName === 'comment') {
97119 var childNodes = comment.childNodes;
97120 var parsedComment = {};
97122 for (var j = 0; j < childNodes.length; j++) {
97123 var node = childNodes[j];
97124 var nodeName = node.nodeName;
97125 if (nodeName === '#text') continue;
97126 parsedComment[nodeName] = node.textContent;
97128 if (nodeName === 'uid') {
97129 var uid = node.textContent;
97131 if (uid && !_userCache.user[uid]) {
97132 _userCache.toLoad[uid] = true;
97137 if (parsedComment) {
97138 parsedComments.push(parsedComment);
97143 return parsedComments;
97146 function encodeNoteRtree(note) {
97156 var jsonparsers = {
97157 node: function nodeData(obj, uid) {
97158 return new osmNode({
97160 visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97161 version: obj.version && obj.version.toString(),
97162 changeset: obj.changeset && obj.changeset.toString(),
97163 timestamp: obj.timestamp,
97165 uid: obj.uid && obj.uid.toString(),
97166 loc: [parseFloat(obj.lon), parseFloat(obj.lat)],
97170 way: function wayData(obj, uid) {
97171 return new osmWay({
97173 visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97174 version: obj.version && obj.version.toString(),
97175 changeset: obj.changeset && obj.changeset.toString(),
97176 timestamp: obj.timestamp,
97178 uid: obj.uid && obj.uid.toString(),
97180 nodes: getNodesJSON(obj)
97183 relation: function relationData(obj, uid) {
97184 return new osmRelation({
97186 visible: typeof obj.visible === 'boolean' ? obj.visible : true,
97187 version: obj.version && obj.version.toString(),
97188 changeset: obj.changeset && obj.changeset.toString(),
97189 timestamp: obj.timestamp,
97191 uid: obj.uid && obj.uid.toString(),
97193 members: getMembersJSON(obj)
97196 user: function parseUser(obj, uid) {
97199 display_name: obj.display_name,
97200 account_created: obj.account_created,
97201 image_url: obj.img && obj.img.href,
97202 changesets_count: obj.changesets && obj.changesets.count && obj.changesets.count.toString() || '0',
97203 active_blocks: obj.blocks && obj.blocks.received && obj.blocks.received.active && obj.blocks.received.active.toString() || '0'
97208 function parseJSON(payload, callback, options) {
97209 options = Object.assign({
97215 message: 'No JSON',
97220 var json = payload;
97221 if (_typeof(json) !== 'object') json = JSON.parse(payload);
97222 if (!json.elements) return callback({
97223 message: 'No JSON',
97226 var children = json.elements;
97227 var handle = window.requestIdleCallback(function () {
97228 _deferred["delete"](handle);
97233 for (var i = 0; i < children.length; i++) {
97234 result = parseChild(children[i]);
97235 if (result) results.push(result);
97238 callback(null, results);
97241 _deferred.add(handle);
97243 function parseChild(child) {
97244 var parser = jsonparsers[child.type];
97245 if (!parser) return null;
97247 uid = osmEntity.id.fromOSM(child.type, child.id);
97249 if (options.skipSeen) {
97250 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
97252 _tileCache.seen[uid] = true;
97255 return parser(child, uid);
97259 function parseUserJSON(payload, callback, options) {
97260 options = Object.assign({
97266 message: 'No JSON',
97271 var json = payload;
97272 if (_typeof(json) !== 'object') json = JSON.parse(payload);
97273 if (!json.users && !json.user) return callback({
97274 message: 'No JSON',
97277 var objs = json.users || [json];
97278 var handle = window.requestIdleCallback(function () {
97279 _deferred["delete"](handle);
97284 for (var i = 0; i < objs.length; i++) {
97285 result = parseObj(objs[i]);
97286 if (result) results.push(result);
97289 callback(null, results);
97292 _deferred.add(handle);
97294 function parseObj(obj) {
97295 var uid = obj.user.id && obj.user.id.toString();
97297 if (options.skipSeen && _userCache.user[uid]) {
97298 delete _userCache.toLoad[uid];
97302 var user = jsonparsers.user(obj.user, uid);
97303 _userCache.user[uid] = user;
97304 delete _userCache.toLoad[uid];
97310 node: function nodeData(obj, uid) {
97311 var attrs = obj.attributes;
97312 return new osmNode({
97314 visible: getVisible(attrs),
97315 version: attrs.version.value,
97316 changeset: attrs.changeset && attrs.changeset.value,
97317 timestamp: attrs.timestamp && attrs.timestamp.value,
97318 user: attrs.user && attrs.user.value,
97319 uid: attrs.uid && attrs.uid.value,
97320 loc: getLoc(attrs),
97324 way: function wayData(obj, uid) {
97325 var attrs = obj.attributes;
97326 return new osmWay({
97328 visible: getVisible(attrs),
97329 version: attrs.version.value,
97330 changeset: attrs.changeset && attrs.changeset.value,
97331 timestamp: attrs.timestamp && attrs.timestamp.value,
97332 user: attrs.user && attrs.user.value,
97333 uid: attrs.uid && attrs.uid.value,
97334 tags: getTags(obj),
97335 nodes: getNodes(obj)
97338 relation: function relationData(obj, uid) {
97339 var attrs = obj.attributes;
97340 return new osmRelation({
97342 visible: getVisible(attrs),
97343 version: attrs.version.value,
97344 changeset: attrs.changeset && attrs.changeset.value,
97345 timestamp: attrs.timestamp && attrs.timestamp.value,
97346 user: attrs.user && attrs.user.value,
97347 uid: attrs.uid && attrs.uid.value,
97348 tags: getTags(obj),
97349 members: getMembers(obj)
97352 note: function parseNote(obj, uid) {
97353 var attrs = obj.attributes;
97354 var childNodes = obj.childNodes;
97357 props.loc = getLoc(attrs); // if notes are coincident, move them apart slightly
97359 var coincident = false;
97360 var epsilon = 0.00001;
97364 props.loc = geoVecAdd(props.loc, [epsilon, epsilon]);
97367 var bbox = geoExtent(props.loc).bbox();
97368 coincident = _noteCache.rtree.search(bbox).length;
97369 } while (coincident); // parse note contents
97372 for (var i = 0; i < childNodes.length; i++) {
97373 var node = childNodes[i];
97374 var nodeName = node.nodeName;
97375 if (nodeName === '#text') continue; // if the element is comments, parse the comments
97377 if (nodeName === 'comments') {
97378 props[nodeName] = parseComments(node.childNodes);
97380 props[nodeName] = node.textContent;
97384 var note = new osmNote(props);
97385 var item = encodeNoteRtree(note);
97386 _noteCache.note[note.id] = note;
97388 _noteCache.rtree.insert(item);
97392 user: function parseUser(obj, uid) {
97393 var attrs = obj.attributes;
97396 display_name: attrs.display_name && attrs.display_name.value,
97397 account_created: attrs.account_created && attrs.account_created.value,
97398 changesets_count: '0',
97401 var img = obj.getElementsByTagName('img');
97403 if (img && img[0] && img[0].getAttribute('href')) {
97404 user.image_url = img[0].getAttribute('href');
97407 var changesets = obj.getElementsByTagName('changesets');
97409 if (changesets && changesets[0] && changesets[0].getAttribute('count')) {
97410 user.changesets_count = changesets[0].getAttribute('count');
97413 var blocks = obj.getElementsByTagName('blocks');
97415 if (blocks && blocks[0]) {
97416 var received = blocks[0].getElementsByTagName('received');
97418 if (received && received[0] && received[0].getAttribute('active')) {
97419 user.active_blocks = received[0].getAttribute('active');
97423 _userCache.user[uid] = user;
97424 delete _userCache.toLoad[uid];
97429 function parseXML(xml, callback, options) {
97430 options = Object.assign({
97434 if (!xml || !xml.childNodes) {
97441 var root = xml.childNodes[0];
97442 var children = root.childNodes;
97443 var handle = window.requestIdleCallback(function () {
97444 _deferred["delete"](handle);
97449 for (var i = 0; i < children.length; i++) {
97450 result = parseChild(children[i]);
97451 if (result) results.push(result);
97454 callback(null, results);
97457 _deferred.add(handle);
97459 function parseChild(child) {
97460 var parser = parsers[child.nodeName];
97461 if (!parser) return null;
97464 if (child.nodeName === 'user') {
97465 uid = child.attributes.id.value;
97467 if (options.skipSeen && _userCache.user[uid]) {
97468 delete _userCache.toLoad[uid];
97471 } else if (child.nodeName === 'note') {
97472 uid = child.getElementsByTagName('id')[0].textContent;
97474 uid = osmEntity.id.fromOSM(child.nodeName, child.attributes.id.value);
97476 if (options.skipSeen) {
97477 if (_tileCache.seen[uid]) return null; // avoid reparsing a "seen" entity
97479 _tileCache.seen[uid] = true;
97483 return parser(child, uid);
97485 } // replace or remove note from rtree
97488 function updateRtree(item, replace) {
97489 _noteCache.rtree.remove(item, function isEql(a, b) {
97490 return a.data.id === b.data.id;
97494 _noteCache.rtree.insert(item);
97498 function wrapcb(thisArg, callback, cid) {
97499 return function (err, result) {
97501 // 400 Bad Request, 401 Unauthorized, 403 Forbidden..
97502 if (err.status === 400 || err.status === 401 || err.status === 403) {
97506 return callback.call(thisArg, err);
97507 } else if (thisArg.getConnectionId() !== cid) {
97508 return callback.call(thisArg, {
97509 message: 'Connection Switched',
97513 return callback.call(thisArg, err, result);
97519 init: function init() {
97520 utilRebind(this, dispatch$2, 'on');
97522 reset: function reset() {
97523 Array.from(_deferred).forEach(function (handle) {
97524 window.cancelIdleCallback(handle);
97526 _deferred["delete"](handle);
97529 _userChangesets = undefined;
97530 _userDetails = undefined;
97531 _rateLimitError = undefined;
97532 Object.values(_tileCache.inflight).forEach(abortRequest$2);
97533 Object.values(_noteCache.inflight).forEach(abortRequest$2);
97534 Object.values(_noteCache.inflightPost).forEach(abortRequest$2);
97535 if (_changeset.inflight) abortRequest$2(_changeset.inflight);
97556 _cachedApiStatus = undefined;
97560 getConnectionId: function getConnectionId() {
97561 return _connectionID;
97563 changesetURL: function changesetURL(changesetID) {
97564 return urlroot + '/changeset/' + changesetID;
97566 changesetsURL: function changesetsURL(center, zoom) {
97567 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
97568 return urlroot + '/history#map=' + Math.floor(zoom) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
97570 entityURL: function entityURL(entity) {
97571 return urlroot + '/' + entity.type + '/' + entity.osmId();
97573 historyURL: function historyURL(entity) {
97574 return urlroot + '/' + entity.type + '/' + entity.osmId() + '/history';
97576 userURL: function userURL(username) {
97577 return urlroot + '/user/' + username;
97579 noteURL: function noteURL(note) {
97580 return urlroot + '/note/' + note.id;
97582 noteReportURL: function noteReportURL(note) {
97583 return urlroot + '/reports/new?reportable_type=Note&reportable_id=' + note.id;
97585 // Generic method to load data from the OSM API
97586 // Can handle either auth or unauth calls.
97587 loadFromAPI: function loadFromAPI(path, callback, options) {
97588 options = Object.assign({
97592 var cid = _connectionID;
97594 function done(err, payload) {
97595 if (that.getConnectionId() !== cid) {
97596 if (callback) callback({
97597 message: 'Connection Switched',
97603 var isAuthenticated = that.authenticated(); // 400 Bad Request, 401 Unauthorized, 403 Forbidden
97604 // Logout and retry the request..
97606 if (isAuthenticated && err && err.status && (err.status === 400 || err.status === 401 || err.status === 403)) {
97608 that.loadFromAPI(path, callback, options); // else, no retry..
97610 // 509 Bandwidth Limit Exceeded, 429 Too Many Requests
97611 // Set the rateLimitError flag and trigger a warning..
97612 if (!isAuthenticated && !_rateLimitError && err && err.status && (err.status === 509 || err.status === 429)) {
97613 _rateLimitError = err;
97614 dispatch$2.call('change');
97615 that.reloadApiStatus();
97616 } else if (err && _cachedApiStatus === 'online' || !err && _cachedApiStatus !== 'online') {
97617 // If the response's error state doesn't match the status,
97618 // it's likely we lost or gained the connection so reload the status
97619 that.reloadApiStatus();
97624 return callback(err);
97626 if (path.indexOf('.json') !== -1) {
97627 return parseJSON(payload, callback, options);
97629 return parseXML(payload, callback, options);
97636 if (this.authenticated()) {
97642 var url = urlroot + path;
97643 var controller = new AbortController();
97646 if (path.indexOf('.json') !== -1) {
97653 signal: controller.signal
97654 }).then(function (data) {
97656 })["catch"](function (err) {
97657 if (err.name === 'AbortError') return; // d3-fetch includes status in the error message,
97658 // but we can't access the response itself
97659 // https://github.com/d3/d3-fetch/issues/27
97661 var match = err.message.match(/^\d{3}/);
97666 statusText: err.message
97675 // Load a single entity by id (ways and relations use the `/full` call to include
97676 // nodes and members). Parent relations are not included, see `loadEntityRelations`.
97677 // GET /api/0.6/node/#id
97678 // GET /api/0.6/[way|relation]/#id/full
97679 loadEntity: function loadEntity(id, callback) {
97680 var type = osmEntity.id.type(id);
97681 var osmID = osmEntity.id.toOSM(id);
97685 this.loadFromAPI('/api/0.6/' + type + '/' + osmID + (type !== 'node' ? '/full' : '') + '.json', function (err, entities) {
97686 if (callback) callback(err, {
97691 // Load a single entity with a specific version
97692 // GET /api/0.6/[node|way|relation]/#id/#version
97693 loadEntityVersion: function loadEntityVersion(id, version, callback) {
97694 var type = osmEntity.id.type(id);
97695 var osmID = osmEntity.id.toOSM(id);
97699 this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/' + version + '.json', function (err, entities) {
97700 if (callback) callback(err, {
97705 // Load the relations of a single entity with the given.
97706 // GET /api/0.6/[node|way|relation]/#id/relations
97707 loadEntityRelations: function loadEntityRelations(id, callback) {
97708 var type = osmEntity.id.type(id);
97709 var osmID = osmEntity.id.toOSM(id);
97713 this.loadFromAPI('/api/0.6/' + type + '/' + osmID + '/relations.json', function (err, entities) {
97714 if (callback) callback(err, {
97719 // Load multiple entities in chunks
97720 // (note: callback may be called multiple times)
97721 // Unlike `loadEntity`, child nodes and members are not fetched
97722 // GET /api/0.6/[nodes|ways|relations]?#parameters
97723 loadMultiple: function loadMultiple(ids, callback) {
97725 var groups = utilArrayGroupBy(utilArrayUniq(ids), osmEntity.id.type);
97726 Object.keys(groups).forEach(function (k) {
97727 var type = k + 's'; // nodes, ways, relations
97729 var osmIDs = groups[k].map(function (id) {
97730 return osmEntity.id.toOSM(id);
97735 utilArrayChunk(osmIDs, 150).forEach(function (arr) {
97736 that.loadFromAPI('/api/0.6/' + type + '.json?' + type + '=' + arr.join(), function (err, entities) {
97737 if (callback) callback(err, {
97744 // Create, upload, and close a changeset
97745 // PUT /api/0.6/changeset/create
97746 // POST /api/0.6/changeset/#id/upload
97747 // PUT /api/0.6/changeset/#id/close
97748 putChangeset: function putChangeset(changeset, changes, callback) {
97749 var cid = _connectionID;
97751 if (_changeset.inflight) {
97753 message: 'Changeset already inflight',
97756 } else if (_changeset.open) {
97757 // reuse existing open changeset..
97758 return createdChangeset.call(this, null, _changeset.open);
97760 // Open a new changeset..
97763 path: '/api/0.6/changeset/create',
97766 'Content-Type': 'text/xml'
97769 content: JXON.stringify(changeset.asJXON())
97771 _changeset.inflight = oauth.xhr(options, wrapcb(this, createdChangeset, cid));
97774 function createdChangeset(err, changesetID) {
97775 _changeset.inflight = null;
97778 return callback(err, changeset);
97781 _changeset.open = changesetID;
97782 changeset = changeset.update({
97784 }); // Upload the changeset..
97788 path: '/api/0.6/changeset/' + changesetID + '/upload',
97791 'Content-Type': 'text/xml'
97794 content: JXON.stringify(changeset.osmChangeJXON(changes))
97796 _changeset.inflight = oauth.xhr(options, wrapcb(this, uploadedChangeset, cid));
97799 function uploadedChangeset(err) {
97800 _changeset.inflight = null;
97801 if (err) return callback(err, changeset); // Upload was successful, safe to call the callback.
97802 // Add delay to allow for postgres replication #1646 #2678
97804 window.setTimeout(function () {
97805 callback(null, changeset);
97807 _changeset.open = null; // At this point, we don't really care if the connection was switched..
97808 // Only try to close the changeset if we're still talking to the same server.
97810 if (this.getConnectionId() === cid) {
97811 // Still attempt to close changeset, but ignore response because #2667
97814 path: '/api/0.6/changeset/' + changeset.id + '/close',
97817 'Content-Type': 'text/xml'
97826 // Load multiple users in chunks
97827 // (note: callback may be called multiple times)
97828 // GET /api/0.6/users?users=#id1,#id2,...,#idn
97829 loadUsers: function loadUsers(uids, callback) {
97832 utilArrayUniq(uids).forEach(function (uid) {
97833 if (_userCache.user[uid]) {
97834 delete _userCache.toLoad[uid];
97835 cached.push(_userCache.user[uid]);
97841 if (cached.length || !this.authenticated()) {
97842 callback(undefined, cached);
97843 if (!this.authenticated()) return; // require auth
97846 utilArrayChunk(toLoad, 150).forEach(function (arr) {
97849 path: '/api/0.6/users.json?users=' + arr.join()
97850 }, wrapcb(this, done, _connectionID));
97853 function done(err, payload) {
97854 if (err) return callback(err);
97858 return parseUserJSON(payload, function (err, results) {
97859 if (err) return callback(err);
97860 return callback(undefined, results);
97864 // Load a given user by id
97865 // GET /api/0.6/user/#id
97866 loadUser: function loadUser(uid, callback) {
97867 if (_userCache.user[uid] || !this.authenticated()) {
97869 delete _userCache.toLoad[uid];
97870 return callback(undefined, _userCache.user[uid]);
97875 path: '/api/0.6/user/' + uid + '.json'
97876 }, wrapcb(this, done, _connectionID));
97878 function done(err, payload) {
97879 if (err) return callback(err);
97883 return parseUserJSON(payload, function (err, results) {
97884 if (err) return callback(err);
97885 return callback(undefined, results[0]);
97889 // Load the details of the logged-in user
97890 // GET /api/0.6/user/details
97891 userDetails: function userDetails(callback) {
97892 if (_userDetails) {
97894 return callback(undefined, _userDetails);
97899 path: '/api/0.6/user/details.json'
97900 }, wrapcb(this, done, _connectionID));
97902 function done(err, payload) {
97903 if (err) return callback(err);
97907 return parseUserJSON(payload, function (err, results) {
97908 if (err) return callback(err);
97909 _userDetails = results[0];
97910 return callback(undefined, _userDetails);
97914 // Load previous changesets for the logged in user
97915 // GET /api/0.6/changesets?user=#id
97916 userChangesets: function userChangesets(callback) {
97917 if (_userChangesets) {
97919 return callback(undefined, _userChangesets);
97922 this.userDetails(wrapcb(this, gotDetails, _connectionID));
97924 function gotDetails(err, user) {
97926 return callback(err);
97931 path: '/api/0.6/changesets?user=' + user.id
97932 }, wrapcb(this, done, _connectionID));
97935 function done(err, xml) {
97937 return callback(err);
97940 _userChangesets = Array.prototype.map.call(xml.getElementsByTagName('changeset'), function (changeset) {
97942 tags: getTags(changeset)
97944 }).filter(function (changeset) {
97945 var comment = changeset.tags.comment;
97946 return comment && comment !== '';
97948 return callback(undefined, _userChangesets);
97951 // Fetch the status of the OSM API
97952 // GET /api/capabilities
97953 status: function status(callback) {
97954 var url = urlroot + '/api/capabilities';
97955 var errback = wrapcb(this, done, _connectionID);
97956 d3_xml(url).then(function (data) {
97957 errback(null, data);
97958 })["catch"](function (err) {
97959 errback(err.message);
97962 function done(err, xml) {
97964 // the status is null if no response could be retrieved
97965 return callback(err, null);
97966 } // update blocklists
97969 var elements = xml.getElementsByTagName('blacklist');
97972 for (var i = 0; i < elements.length; i++) {
97973 var regexString = elements[i].getAttribute('regex'); // needs unencode?
97977 var regex = new RegExp(regexString);
97978 regexes.push(regex);
97985 if (regexes.length) {
97986 _imageryBlocklists = regexes;
97989 if (_rateLimitError) {
97990 return callback(_rateLimitError, 'rateLimited');
97992 var waynodes = xml.getElementsByTagName('waynodes');
97993 var maxWayNodes = waynodes.length && parseInt(waynodes[0].getAttribute('maximum'), 10);
97994 if (maxWayNodes && isFinite(maxWayNodes)) _maxWayNodes = maxWayNodes;
97995 var apiStatus = xml.getElementsByTagName('status');
97996 var val = apiStatus[0].getAttribute('api');
97997 return callback(undefined, val);
98001 // Calls `status` and dispatches an `apiStatusChange` event if the returned
98002 // status differs from the cached status.
98003 reloadApiStatus: function reloadApiStatus() {
98004 // throttle to avoid unnecessary API calls
98005 if (!this.throttledReloadApiStatus) {
98007 this.throttledReloadApiStatus = throttle(function () {
98008 that.status(function (err, status) {
98009 if (status !== _cachedApiStatus) {
98010 _cachedApiStatus = status;
98011 dispatch$2.call('apiStatusChange', that, err, status);
98017 this.throttledReloadApiStatus();
98019 // Returns the maximum number of nodes a single way can have
98020 maxWayNodes: function maxWayNodes() {
98021 return _maxWayNodes;
98023 // Load data (entities) from the API in tiles
98024 // GET /api/0.6/map?bbox=
98025 loadTiles: function loadTiles(projection, callback) {
98026 if (_off) return; // determine the needed tiles to cover the view
98028 var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection); // abort inflight requests that are no longer needed
98030 var hadRequests = hasInflightRequests(_tileCache);
98031 abortUnwantedRequests(_tileCache, tiles);
98033 if (hadRequests && !hasInflightRequests(_tileCache)) {
98034 dispatch$2.call('loaded'); // stop the spinner
98035 } // issue new requests..
98038 tiles.forEach(function (tile) {
98039 this.loadTile(tile, callback);
98042 // Load a single data tile
98043 // GET /api/0.6/map?bbox=
98044 loadTile: function loadTile(tile, callback) {
98046 if (_tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
98048 if (!hasInflightRequests(_tileCache)) {
98049 dispatch$2.call('loading'); // start the spinner
98052 var path = '/api/0.6/map.json?bbox=';
98056 _tileCache.inflight[tile.id] = this.loadFromAPI(path + tile.extent.toParam(), tileCallback, options);
98058 function tileCallback(err, parsed) {
98059 delete _tileCache.inflight[tile.id];
98062 delete _tileCache.toLoad[tile.id];
98063 _tileCache.loaded[tile.id] = true;
98064 var bbox = tile.extent.bbox();
98067 _tileCache.rtree.insert(bbox);
98071 callback(err, Object.assign({
98076 if (!hasInflightRequests(_tileCache)) {
98077 dispatch$2.call('loaded'); // stop the spinner
98081 isDataLoaded: function isDataLoaded(loc) {
98088 return _tileCache.rtree.collides(bbox);
98090 // load the tile that covers the given `loc`
98091 loadTileAtLoc: function loadTileAtLoc(loc, callback) {
98092 // Back off if the toLoad queue is filling up.. re #6417
98093 // (Currently `loadTileAtLoc` requests are considered low priority - used by operations to
98094 // let users safely edit geometries which extend to unloaded tiles. We can drop some.)
98095 if (Object.keys(_tileCache.toLoad).length > 50) return;
98096 var k = geoZoomToScale(_tileZoom + 1);
98097 var offset = geoRawMercator().scale(k)(loc);
98098 var projection = geoRawMercator().transform({
98103 var tiles = tiler$2.zoomExtent([_tileZoom, _tileZoom]).getTiles(projection);
98104 tiles.forEach(function (tile) {
98105 if (_tileCache.toLoad[tile.id] || _tileCache.loaded[tile.id] || _tileCache.inflight[tile.id]) return;
98106 _tileCache.toLoad[tile.id] = true;
98107 this.loadTile(tile, callback);
98110 // Load notes from the API in tiles
98111 // GET /api/0.6/notes?bbox=
98112 loadNotes: function loadNotes(projection, noteOptions) {
98113 noteOptions = Object.assign({
98119 var path = '/api/0.6/notes?limit=' + noteOptions.limit + '&closed=' + noteOptions.closed + '&bbox=';
98121 var throttleLoadUsers = throttle(function () {
98122 var uids = Object.keys(_userCache.toLoad);
98123 if (!uids.length) return;
98124 that.loadUsers(uids, function () {}); // eagerly load user details
98125 }, 750); // determine the needed tiles to cover the view
98128 var tiles = tiler$2.zoomExtent([_noteZoom, _noteZoom]).getTiles(projection); // abort inflight requests that are no longer needed
98130 abortUnwantedRequests(_noteCache, tiles); // issue new requests..
98132 tiles.forEach(function (tile) {
98133 if (_noteCache.loaded[tile.id] || _noteCache.inflight[tile.id]) return;
98137 _noteCache.inflight[tile.id] = that.loadFromAPI(path + tile.extent.toParam(), function (err) {
98138 delete _noteCache.inflight[tile.id];
98141 _noteCache.loaded[tile.id] = true;
98144 throttleLoadUsers();
98145 dispatch$2.call('loadedNotes');
98150 // POST /api/0.6/notes?params
98151 postNoteCreate: function postNoteCreate(note, callback) {
98152 if (!this.authenticated()) {
98154 message: 'Not Authenticated',
98159 if (_noteCache.inflightPost[note.id]) {
98161 message: 'Note update already inflight',
98166 if (!note.loc[0] || !note.loc[1] || !note.newComment) return; // location & description required
98168 var comment = note.newComment;
98170 if (note.newCategory && note.newCategory !== 'None') {
98171 comment += ' #' + note.newCategory;
98174 var path = '/api/0.6/notes?' + utilQsString({
98179 _noteCache.inflightPost[note.id] = oauth.xhr({
98182 }, wrapcb(this, done, _connectionID));
98184 function done(err, xml) {
98185 delete _noteCache.inflightPost[note.id];
98188 return callback(err);
98189 } // we get the updated note back, remove from caches and reparse..
98192 this.removeNote(note);
98196 return parseXML(xml, function (err, results) {
98198 return callback(err);
98200 return callback(undefined, results[0]);
98206 // POST /api/0.6/notes/#id/comment?text=comment
98207 // POST /api/0.6/notes/#id/close?text=comment
98208 // POST /api/0.6/notes/#id/reopen?text=comment
98209 postNoteUpdate: function postNoteUpdate(note, newStatus, callback) {
98210 if (!this.authenticated()) {
98212 message: 'Not Authenticated',
98217 if (_noteCache.inflightPost[note.id]) {
98219 message: 'Note update already inflight',
98226 if (note.status !== 'closed' && newStatus === 'closed') {
98228 } else if (note.status !== 'open' && newStatus === 'open') {
98231 action = 'comment';
98232 if (!note.newComment) return; // when commenting, comment required
98235 var path = '/api/0.6/notes/' + note.id + '/' + action;
98237 if (note.newComment) {
98238 path += '?' + utilQsString({
98239 text: note.newComment
98243 _noteCache.inflightPost[note.id] = oauth.xhr({
98246 }, wrapcb(this, done, _connectionID));
98248 function done(err, xml) {
98249 delete _noteCache.inflightPost[note.id];
98252 return callback(err);
98253 } // we get the updated note back, remove from caches and reparse..
98256 this.removeNote(note); // update closed note cache - used to populate `closed:note` changeset tag
98258 if (action === 'close') {
98259 _noteCache.closed[note.id] = true;
98260 } else if (action === 'reopen') {
98261 delete _noteCache.closed[note.id];
98267 return parseXML(xml, function (err, results) {
98269 return callback(err);
98271 return callback(undefined, results[0]);
98276 "switch": function _switch(options) {
98277 urlroot = options.urlroot;
98278 oauth.options(Object.assign({
98280 loading: authLoading,
98284 this.userChangesets(function () {}); // eagerly load user details/changesets
98286 dispatch$2.call('change');
98289 toggle: function toggle(val) {
98293 isChangesetInflight: function isChangesetInflight() {
98294 return !!_changeset.inflight;
98296 // get/set cached data
98297 // This is used to save/restore the state when entering/exiting the walkthrough
98298 // Also used for testing purposes.
98299 caches: function caches(obj) {
98300 function cloneCache(source) {
98302 Object.keys(source).forEach(function (k) {
98303 if (k === 'rtree') {
98304 target.rtree = new RBush().fromJSON(source.rtree.toJSON()); // clone rbush
98305 } else if (k === 'note') {
98307 Object.keys(source.note).forEach(function (id) {
98308 target.note[id] = osmNote(source.note[id]); // copy notes
98311 target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep
98317 if (!arguments.length) {
98319 tile: cloneCache(_tileCache),
98320 note: cloneCache(_noteCache),
98321 user: cloneCache(_userCache)
98323 } // access caches directly for testing (e.g., loading notes rtree)
98326 if (obj === 'get') {
98335 _tileCache = obj.tile;
98336 _tileCache.inflight = {};
98340 _noteCache = obj.note;
98341 _noteCache.inflight = {};
98342 _noteCache.inflightPost = {};
98346 _userCache = obj.user;
98351 logout: function logout() {
98352 _userChangesets = undefined;
98353 _userDetails = undefined;
98355 dispatch$2.call('change');
98358 authenticated: function authenticated() {
98359 return oauth.authenticated();
98361 authenticate: function authenticate(callback) {
98363 var cid = _connectionID;
98364 _userChangesets = undefined;
98365 _userDetails = undefined;
98367 function done(err, res) {
98369 if (callback) callback(err);
98373 if (that.getConnectionId() !== cid) {
98374 if (callback) callback({
98375 message: 'Connection Switched',
98381 _rateLimitError = undefined;
98382 dispatch$2.call('change');
98383 if (callback) callback(err, res);
98384 that.userChangesets(function () {}); // eagerly load user details/changesets
98387 return oauth.authenticate(done);
98389 imageryBlocklists: function imageryBlocklists() {
98390 return _imageryBlocklists;
98392 tileZoom: function tileZoom(val) {
98393 if (!arguments.length) return _tileZoom;
98397 // get all cached notes covering the viewport
98398 notes: function notes(projection) {
98399 var viewport = projection.clipExtent();
98400 var min = [viewport[0][0], viewport[1][1]];
98401 var max = [viewport[1][0], viewport[0][1]];
98402 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
98403 return _noteCache.rtree.search(bbox).map(function (d) {
98407 // get a single note from the cache
98408 getNote: function getNote(id) {
98409 return _noteCache.note[id];
98411 // remove a single note from the cache
98412 removeNote: function removeNote(note) {
98413 if (!(note instanceof osmNote) || !note.id) return;
98414 delete _noteCache.note[note.id];
98415 updateRtree(encodeNoteRtree(note), false); // false = remove
98417 // replace a single note in the cache
98418 replaceNote: function replaceNote(note) {
98419 if (!(note instanceof osmNote) || !note.id) return;
98420 _noteCache.note[note.id] = note;
98421 updateRtree(encodeNoteRtree(note), true); // true = replace
98425 // Get an array of note IDs closed during this session.
98426 // Used to populate `closed:note` changeset tag
98427 getClosedIDs: function getClosedIDs() {
98428 return Object.keys(_noteCache.closed).sort();
98432 var _apibase$1 = 'https://wiki.openstreetmap.org/w/api.php';
98433 var _inflight$1 = {};
98434 var _wikibaseCache = {};
98439 var debouncedRequest$1 = debounce(request$1, 500, {
98443 function request$1(url, callback) {
98444 if (_inflight$1[url]) return;
98445 var controller = new AbortController();
98446 _inflight$1[url] = controller;
98448 signal: controller.signal
98449 }).then(function (result) {
98450 delete _inflight$1[url];
98451 if (callback) callback(null, result);
98452 })["catch"](function (err) {
98453 delete _inflight$1[url];
98454 if (err.name === 'AbortError') return;
98455 if (callback) callback(err.message);
98459 var serviceOsmWikibase = {
98460 init: function init() {
98462 _wikibaseCache = {};
98465 reset: function reset() {
98466 Object.values(_inflight$1).forEach(function (controller) {
98467 controller.abort();
98473 * Get the best value for the property, or undefined if not found
98474 * @param entity object from wikibase
98475 * @param property string e.g. 'P4' for image
98476 * @param langCode string e.g. 'fr' for French
98478 claimToValue: function claimToValue(entity, property, langCode) {
98479 if (!entity.claims[property]) return undefined;
98480 var locale = _localeIDs[langCode];
98481 var preferredPick, localePick;
98482 entity.claims[property].forEach(function (stmt) {
98483 // If exists, use value limited to the needed language (has a qualifier P26 = locale)
98484 // Or if not found, use the first value with the "preferred" rank
98485 if (!preferredPick && stmt.rank === 'preferred') {
98486 preferredPick = stmt;
98489 if (locale && stmt.qualifiers && stmt.qualifiers.P26 && stmt.qualifiers.P26[0].datavalue.value.id === locale) {
98493 var result = localePick || preferredPick;
98496 var datavalue = result.mainsnak.datavalue;
98497 return datavalue.type === 'wikibase-entityid' ? datavalue.value.id : datavalue.value;
98504 * Convert monolingual property into a key-value object (language -> value)
98505 * @param entity object from wikibase
98506 * @param property string e.g. 'P31' for monolingual wiki page title
98508 monolingualClaimToValueObj: function monolingualClaimToValueObj(entity, property) {
98509 if (!entity || !entity.claims[property]) return undefined;
98510 return entity.claims[property].reduce(function (acc, obj) {
98511 var value = obj.mainsnak.datavalue.value;
98512 acc[value.language] = value.text;
98516 toSitelink: function toSitelink(key, value) {
98517 var result = value ? 'Tag:' + key + '=' + value : 'Key:' + key;
98518 return result.replace(/_/g, ' ').trim();
98521 // Pass params object of the form:
98524 // value: 'string',
98525 // langCode: 'string'
98528 getEntity: function getEntity(params, callback) {
98529 var doRequest = params.debounce ? debouncedRequest$1 : request$1;
98533 var rtypeSitelink = params.key === 'type' && params.value ? ('Relation:' + params.value).replace(/_/g, ' ').trim() : false;
98534 var keySitelink = params.key ? this.toSitelink(params.key) : false;
98535 var tagSitelink = params.key && params.value ? this.toSitelink(params.key, params.value) : false;
98536 var localeSitelink;
98538 if (params.langCodes) {
98539 params.langCodes.forEach(function (langCode) {
98540 if (_localeIDs[langCode] === undefined) {
98541 // If this is the first time we are asking about this locale,
98542 // fetch corresponding entity (if it exists), and cache it.
98543 // If there is no such entry, cache `false` value to avoid re-requesting it.
98544 localeSitelink = ('Locale:' + langCode).replace(/_/g, ' ').trim();
98545 titles.push(localeSitelink);
98550 if (rtypeSitelink) {
98551 if (_wikibaseCache[rtypeSitelink]) {
98552 result.rtype = _wikibaseCache[rtypeSitelink];
98554 titles.push(rtypeSitelink);
98559 if (_wikibaseCache[keySitelink]) {
98560 result.key = _wikibaseCache[keySitelink];
98562 titles.push(keySitelink);
98567 if (_wikibaseCache[tagSitelink]) {
98568 result.tag = _wikibaseCache[tagSitelink];
98570 titles.push(tagSitelink);
98574 if (!titles.length) {
98575 // Nothing to do, we already had everything in the cache
98576 return callback(null, result);
98577 } // Requesting just the user language code
98578 // If backend recognizes the code, it will perform proper fallbacks,
98579 // and the result will contain the requested code. If not, all values are returned:
98580 // {"zh-tw":{"value":"...","language":"zh-tw","source-language":"zh-hant"}
98581 // {"pt-br":{"value":"...","language":"pt","for-language":"pt-br"}}
98585 action: 'wbgetentities',
98587 titles: titles.join('|'),
98588 languages: params.langCodes.join('|'),
98589 languagefallback: 1,
98591 format: 'json' // There is an MW Wikibase API bug https://phabricator.wikimedia.org/T212069
98592 // We shouldn't use v1 until it gets fixed, but should switch to it afterwards
98593 // formatversion: 2,
98596 var url = _apibase$1 + '?' + utilQsString(obj);
98597 doRequest(url, function (err, d) {
98600 } else if (!d.success || d.error) {
98601 callback(d.error.messages.map(function (v) {
98602 return v.html['*'];
98605 var localeID = false;
98606 Object.values(d.entities).forEach(function (res) {
98607 if (res.missing !== '') {
98608 var title = res.sitelinks.wiki.title;
98610 if (title === rtypeSitelink) {
98611 _wikibaseCache[rtypeSitelink] = res;
98612 result.rtype = res;
98613 } else if (title === keySitelink) {
98614 _wikibaseCache[keySitelink] = res;
98616 } else if (title === tagSitelink) {
98617 _wikibaseCache[tagSitelink] = res;
98619 } else if (title === localeSitelink) {
98622 console.log('Unexpected title ' + title); // eslint-disable-line no-console
98627 if (localeSitelink) {
98628 // If locale ID is not found, store false to prevent repeated queries
98629 that.addLocale(params.langCodes[0], localeID);
98632 callback(null, result);
98637 // Pass params object of the form:
98639 // key: 'string', // required
98640 // value: 'string' // optional
98643 // Get an result object used to display tag documentation
98645 // title: 'string',
98646 // description: 'string',
98647 // editURL: 'string',
98648 // imageURL: 'string',
98649 // wiki: { title: 'string', text: 'string', url: 'string' }
98652 getDocs: function getDocs(params, callback) {
98654 var langCodes = _mainLocalizer.localeCodes().map(function (code) {
98655 return code.toLowerCase();
98657 params.langCodes = langCodes;
98658 this.getEntity(params, function (err, data) {
98664 var entity = data.rtype || data.tag || data.key;
98667 callback('No entity');
98674 for (i in langCodes) {
98675 var _code = langCodes[i];
98677 if (entity.descriptions[_code] && entity.descriptions[_code].language === _code) {
98678 description = entity.descriptions[_code];
98683 if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
98686 title: entity.title,
98687 description: description ? description.value : '',
98688 descriptionLocaleCode: description ? description.language : '',
98689 editURL: 'https://wiki.openstreetmap.org/wiki/' + entity.title
98692 if (entity.claims) {
98694 var image = that.claimToValue(entity, 'P4', langCodes[0]);
98697 imageroot = 'https://commons.wikimedia.org/w/index.php';
98699 image = that.claimToValue(entity, 'P28', langCodes[0]);
98702 imageroot = 'https://wiki.openstreetmap.org/w/index.php';
98706 if (imageroot && image) {
98707 result.imageURL = imageroot + '?' + utilQsString({
98708 title: 'Special:Redirect/file/' + image,
98712 } // Try to get a wiki page from tag data item first, followed by the corresponding key data item.
98713 // If neither tag nor key data item contain a wiki page in the needed language nor English,
98714 // get the first found wiki page from either the tag or the key item.
98717 var rtypeWiki = that.monolingualClaimToValueObj(data.rtype, 'P31');
98718 var tagWiki = that.monolingualClaimToValueObj(data.tag, 'P31');
98719 var keyWiki = that.monolingualClaimToValueObj(data.key, 'P31');
98720 var wikis = [rtypeWiki, tagWiki, keyWiki];
98723 var wiki = wikis[i];
98725 for (var j in langCodes) {
98726 var code = langCodes[j];
98727 var referenceId = langCodes[0].split('-')[0] !== 'en' && code.split('-')[0] === 'en' ? 'inspector.wiki_en_reference' : 'inspector.wiki_reference';
98728 var info = getWikiInfo(wiki, code, referenceId);
98731 result.wiki = info;
98736 if (result.wiki) break;
98739 callback(null, result); // Helper method to get wiki info if a given language exists
98741 function getWikiInfo(wiki, langCode, tKey) {
98742 if (wiki && wiki[langCode]) {
98744 title: wiki[langCode],
98746 url: 'https://wiki.openstreetmap.org/wiki/' + wiki[langCode]
98752 addLocale: function addLocale(langCode, qid) {
98753 // Makes it easier to unit test
98754 _localeIDs[langCode] = qid;
98756 apibase: function apibase(val) {
98757 if (!arguments.length) return _apibase$1;
98763 var jsonpCache = {};
98764 window.jsonpCache = jsonpCache;
98765 function jsonpRequest(url, callback) {
98767 abort: function abort() {}
98770 if (window.JSONP_FIX) {
98771 if (window.JSONP_DELAY === 0) {
98772 callback(window.JSONP_FIX);
98774 var t = window.setTimeout(function () {
98775 callback(window.JSONP_FIX);
98776 }, window.JSONP_DELAY || 0);
98778 request.abort = function () {
98779 window.clearTimeout(t);
98787 var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
98792 c += chars.charAt(Math.floor(Math.random() * 52));
98798 function create(url) {
98799 var e = url.match(/callback=(\w+)/);
98800 var c = e ? e[1] : rand();
98802 jsonpCache[c] = function (data) {
98803 if (jsonpCache[c]) {
98810 function finalize() {
98811 delete jsonpCache[c];
98815 request.abort = finalize;
98816 return 'jsonpCache.' + c;
98819 var cb = create(url);
98820 var script = select('head').append('script').attr('type', 'text/javascript').attr('src', url.replace(/(\{|%7B)callback(\}|%7D)/, cb));
98824 var bubbleApi = 'https://dev.virtualearth.net/mapcontrol/HumanScaleServices/GetBubbles.ashx?';
98825 var streetsideImagesApi = 'https://t.ssl.ak.tiles.virtualearth.net/tiles/';
98826 var bubbleAppKey = 'AuftgJsO0Xs8Ts4M1xZUQJQXJNsvmh3IV8DkNieCiy3tCwCUMq76-WpkrBtNAuEm';
98827 var pannellumViewerCSS = 'pannellum-streetside/pannellum.css';
98828 var pannellumViewerJS = 'pannellum-streetside/pannellum.js';
98829 var maxResults = 2000;
98830 var tileZoom = 16.5;
98831 var tiler$1 = utilTiler().zoomExtent([tileZoom, tileZoom]).skipNullIsland(true);
98832 var dispatch$1 = dispatch$8('loadedImages', 'viewerChanged');
98833 var minHfov = 10; // zoom in degrees: 20, 10, 5
98835 var maxHfov = 90; // zoom out degrees
98837 var defaultHfov = 45;
98838 var _hires = false;
98839 var _resolution = 512; // higher numbers are slower - 512, 1024, 2048, 4096
98841 var _currScene = 0;
98845 var _pannellumViewer;
98847 var _sceneOptions = {
98848 showFullscreenCtrl: false,
98859 var _loadViewerPromise;
98865 function abortRequest$1(i) {
98869 * localeTimeStamp().
98873 function localeTimestamp(s) {
98874 if (!s) return null;
98880 var d = new Date(s);
98881 if (isNaN(d.getTime())) return null;
98882 return d.toLocaleString(_mainLocalizer.localeCode(), options);
98885 * loadTiles() wraps the process of generating tiles and then fetching image points for each tile.
98889 function loadTiles(which, url, projection, margin) {
98890 var tiles = tiler$1.margin(margin).getTiles(projection); // abort inflight requests that are no longer needed
98892 var cache = _ssCache[which];
98893 Object.keys(cache.inflight).forEach(function (k) {
98894 var wanted = tiles.find(function (tile) {
98895 return k.indexOf(tile.id + ',') === 0;
98899 abortRequest$1(cache.inflight[k]);
98900 delete cache.inflight[k];
98903 tiles.forEach(function (tile) {
98904 return loadNextTilePage(which, url, tile);
98908 * loadNextTilePage() load data for the next tile page in line.
98912 function loadNextTilePage(which, url, tile) {
98913 var cache = _ssCache[which];
98914 var nextPage = cache.nextPage[tile.id] || 0;
98915 var id = tile.id + ',' + String(nextPage);
98916 if (cache.loaded[id] || cache.inflight[id]) return;
98917 cache.inflight[id] = getBubbles(url, tile, function (bubbles) {
98918 cache.loaded[id] = true;
98919 delete cache.inflight[id];
98920 if (!bubbles) return; // [].shift() removes the first element, some statistics info, not a bubble point
98923 var features = bubbles.map(function (bubble) {
98924 if (cache.points[bubble.id]) return null; // skip duplicates
98926 var loc = [bubble.lo, bubble.la];
98931 captured_at: bubble.cd,
98932 captured_by: 'microsoft',
98933 // nbn: bubble.nbn,
98934 // pbn: bubble.pbn,
98944 cache.points[bubble.id] = d; // a sequence starts here
98946 if (bubble.pr === undefined) {
98947 cache.leaders.push(bubble.id);
98957 }).filter(Boolean);
98958 cache.rtree.load(features);
98959 connectSequences();
98961 if (which === 'bubbles') {
98962 dispatch$1.call('loadedImages');
98965 } // call this sometimes to connect the bubbles into sequences
98968 function connectSequences() {
98969 var cache = _ssCache.bubbles;
98970 var keepLeaders = [];
98972 for (var i = 0; i < cache.leaders.length; i++) {
98973 var bubble = cache.points[cache.leaders[i]];
98974 var seen = {}; // try to make a sequence.. use the key of the leader bubble.
98980 var complete = false;
98983 sequence.bubbles.push(bubble);
98984 seen[bubble.key] = true;
98986 if (bubble.ne === undefined) {
98989 bubble = cache.points[bubble.ne]; // advance to next
98991 } while (bubble && !seen[bubble.key] && !complete);
98994 _ssCache.sequences[sequence.key] = sequence; // assign bubbles to the sequence
98996 for (var j = 0; j < sequence.bubbles.length; j++) {
98997 sequence.bubbles[j].sequenceKey = sequence.key;
98998 } // create a GeoJSON LineString
99001 sequence.geojson = {
99002 type: 'LineString',
99004 captured_at: sequence.bubbles[0] ? sequence.bubbles[0].captured_at : null,
99005 captured_by: sequence.bubbles[0] ? sequence.bubbles[0].captured_by : null,
99008 coordinates: sequence.bubbles.map(function (d) {
99013 keepLeaders.push(cache.leaders[i]);
99015 } // couldn't complete these, save for later
99018 cache.leaders = keepLeaders;
99021 * getBubbles() handles the request to the server for a tile extent of 'bubbles' (streetside image locations).
99025 function getBubbles(url, tile, callback) {
99026 var rect = tile.extent.rectangle();
99027 var urlForRequest = url + utilQsString({
99033 appkey: bubbleAppKey,
99034 jsCallback: '{callback}'
99036 return jsonpRequest(urlForRequest, function (data) {
99037 if (!data || data.error) {
99043 } // partition viewport into higher zoom tiles
99046 function partitionViewport(projection) {
99047 var z = geoScaleToZoom(projection.scale());
99048 var z2 = Math.ceil(z * 2) / 2 + 2.5; // round to next 0.5 and add 2.5
99050 var tiler = utilTiler().zoomExtent([z2, z2]);
99051 return tiler.getTiles(projection).map(function (tile) {
99052 return tile.extent;
99054 } // no more than `limit` results per partition.
99057 function searchLimited(limit, projection, rtree) {
99058 limit = limit || 5;
99059 return partitionViewport(projection).reduce(function (result, extent) {
99060 var found = rtree.search(extent.bbox()).slice(0, limit).map(function (d) {
99063 return found.length ? result.concat(found) : result;
99071 function loadImage(imgInfo) {
99072 return new Promise(function (resolve) {
99073 var img = new Image();
99075 img.onload = function () {
99076 var canvas = document.getElementById('ideditor-canvas' + imgInfo.face);
99077 var ctx = canvas.getContext('2d');
99078 ctx.drawImage(img, imgInfo.x, imgInfo.y);
99085 img.onerror = function () {
99092 img.setAttribute('crossorigin', '');
99093 img.src = imgInfo.url;
99101 function loadCanvas(imageGroup) {
99102 return Promise.all(imageGroup.map(loadImage)).then(function (data) {
99103 var canvas = document.getElementById('ideditor-canvas' + data[0].imgInfo.face);
99112 var face = data[0].imgInfo.face;
99113 _sceneOptions.cubeMap[which[face]] = canvas.toDataURL('image/jpeg', 1.0);
99115 status: 'loadCanvas for face ' + data[0].imgInfo.face + 'ok'
99124 function loadFaces(faceGroup) {
99125 return Promise.all(faceGroup.map(loadCanvas)).then(function () {
99127 status: 'loadFaces done'
99132 function setupCanvas(selection, reset) {
99134 selection.selectAll('#ideditor-stitcher-canvases').remove();
99135 } // Add the Streetside working canvases. These are used for 'stitching', or combining,
99136 // multiple images for each of the six faces, before passing to the Pannellum control as DataUrls
99139 selection.selectAll('#ideditor-stitcher-canvases').data([0]).enter().append('div').attr('id', 'ideditor-stitcher-canvases').attr('display', 'none').selectAll('canvas').data(['canvas01', 'canvas02', 'canvas03', 'canvas10', 'canvas11', 'canvas12']).enter().append('canvas').attr('id', function (d) {
99140 return 'ideditor-' + d;
99141 }).attr('width', _resolution).attr('height', _resolution);
99144 function qkToXY(qk) {
99149 for (var i = qk.length; i > 0; i--) {
99150 var key = qk[i - 1];
99151 x += +(key === '1' || key === '3') * scale;
99152 y += +(key === '2' || key === '3') * scale;
99159 function getQuadKeys() {
99160 var dim = _resolution / 256;
99164 quadKeys = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111', '0002', '0003', '0012', '0013', '0102', '0103', '0112', '0113', '1002', '1003', '1012', '1013', '1102', '1103', '1112', '1113', '0020', '0021', '0030', '0031', '0120', '0121', '0130', '0131', '1020', '1021', '1030', '1031', '1120', '1121', '1130', '1131', '0022', '0023', '0032', '0033', '0122', '0123', '0132', '0133', '1022', '1023', '1032', '1033', '1122', '1123', '1132', '1133', '0200', '0201', '0210', '0211', '0300', '0301', '0310', '0311', '1200', '1201', '1210', '1211', '1300', '1301', '1310', '1311', '0202', '0203', '0212', '0213', '0302', '0303', '0312', '0313', '1202', '1203', '1212', '1213', '1302', '1303', '1312', '1313', '0220', '0221', '0230', '0231', '0320', '0321', '0330', '0331', '1220', '1221', '1230', '1231', '1320', '1321', '1330', '1331', '0222', '0223', '0232', '0233', '0322', '0323', '0332', '0333', '1222', '1223', '1232', '1233', '1322', '1323', '1332', '1333', '2000', '2001', '2010', '2011', '2100', '2101', '2110', '2111', '3000', '3001', '3010', '3011', '3100', '3101', '3110', '3111', '2002', '2003', '2012', '2013', '2102', '2103', '2112', '2113', '3002', '3003', '3012', '3013', '3102', '3103', '3112', '3113', '2020', '2021', '2030', '2031', '2120', '2121', '2130', '2131', '3020', '3021', '3030', '3031', '3120', '3121', '3130', '3131', '2022', '2023', '2032', '2033', '2122', '2123', '2132', '2133', '3022', '3023', '3032', '3033', '3122', '3123', '3132', '3133', '2200', '2201', '2210', '2211', '2300', '2301', '2310', '2311', '3200', '3201', '3210', '3211', '3300', '3301', '3310', '3311', '2202', '2203', '2212', '2213', '2302', '2303', '2312', '2313', '3202', '3203', '3212', '3213', '3302', '3303', '3312', '3313', '2220', '2221', '2230', '2231', '2320', '2321', '2330', '2331', '3220', '3221', '3230', '3231', '3320', '3321', '3330', '3331', '2222', '2223', '2232', '2233', '2322', '2323', '2332', '2333', '3222', '3223', '3232', '3233', '3322', '3323', '3332', '3333'];
99165 } else if (dim === 8) {
99166 quadKeys = ['000', '001', '010', '011', '100', '101', '110', '111', '002', '003', '012', '013', '102', '103', '112', '113', '020', '021', '030', '031', '120', '121', '130', '131', '022', '023', '032', '033', '122', '123', '132', '133', '200', '201', '210', '211', '300', '301', '310', '311', '202', '203', '212', '213', '302', '303', '312', '313', '220', '221', '230', '231', '320', '321', '330', '331', '222', '223', '232', '233', '322', '323', '332', '333'];
99167 } else if (dim === 4) {
99168 quadKeys = ['00', '01', '10', '11', '02', '03', '12', '13', '20', '21', '30', '31', '22', '23', '32', '33'];
99171 quadKeys = ['0', '1', '2', '3'];
99177 var serviceStreetside = {
99179 * init() initialize streetside.
99181 init: function init() {
99186 this.event = utilRebind(this, dispatch$1, 'on');
99190 * reset() reset the cache.
99192 reset: function reset() {
99194 Object.values(_ssCache.bubbles.inflight).forEach(abortRequest$1);
99202 rtree: new RBush(),
99213 bubbles: function bubbles(projection) {
99215 return searchLimited(limit, projection, _ssCache.bubbles.rtree);
99217 cachedImage: function cachedImage(imageKey) {
99218 return _ssCache.bubbles.points[imageKey];
99220 sequences: function sequences(projection) {
99221 var viewport = projection.clipExtent();
99222 var min = [viewport[0][0], viewport[1][1]];
99223 var max = [viewport[1][0], viewport[0][1]];
99224 var bbox = geoExtent(projection.invert(min), projection.invert(max)).bbox();
99226 var results = []; // all sequences for bubbles in viewport
99228 _ssCache.bubbles.rtree.search(bbox).forEach(function (d) {
99229 var key = d.data.sequenceKey;
99231 if (key && !seen[key]) {
99233 results.push(_ssCache.sequences[key].geojson);
99243 loadBubbles: function loadBubbles(projection, margin) {
99244 // by default: request 2 nearby tiles so we can connect sequences.
99245 if (margin === undefined) margin = 2;
99246 loadTiles('bubbles', bubbleApi, projection, margin);
99248 viewer: function viewer() {
99249 return _pannellumViewer;
99251 initViewer: function initViewer() {
99252 if (!window.pannellum) return;
99253 if (_pannellumViewer) return;
99256 var sceneID = _currScene.toString();
99260 firstScene: sceneID
99264 options.scenes[sceneID] = _sceneOptions;
99265 _pannellumViewer = window.pannellum.viewer('ideditor-viewer-streetside', options);
99267 ensureViewerLoaded: function ensureViewerLoaded(context) {
99268 if (_loadViewerPromise) return _loadViewerPromise; // create ms-wrapper, a photo wrapper class
99270 var wrap = context.container().select('.photoviewer').selectAll('.ms-wrapper').data([0]); // inject ms-wrapper into the photoviewer div
99271 // (used by all to house each custom photo viewer)
99273 var wrapEnter = wrap.enter().append('div').attr('class', 'photo-wrapper ms-wrapper').classed('hide', true);
99275 var pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse'; // inject div to support streetside viewer (pannellum) and attribution line
99277 wrapEnter.append('div').attr('id', 'ideditor-viewer-streetside').on(pointerPrefix + 'down.streetside', function () {
99278 select(window).on(pointerPrefix + 'move.streetside', function () {
99279 dispatch$1.call('viewerChanged');
99281 }).on(pointerPrefix + 'up.streetside pointercancel.streetside', function () {
99282 select(window).on(pointerPrefix + 'move.streetside', null); // continue dispatching events for a few seconds, in case viewer has inertia.
99284 var t = timer(function (elapsed) {
99285 dispatch$1.call('viewerChanged');
99287 if (elapsed > 2000) {
99291 }).append('div').attr('class', 'photo-attribution fillD');
99292 var controlsEnter = wrapEnter.append('div').attr('class', 'photo-controls-wrap').append('div').attr('class', 'photo-controls');
99293 controlsEnter.append('button').on('click.back', step(-1)).html('◄');
99294 controlsEnter.append('button').on('click.forward', step(1)).html('►'); // create working canvas for stitching together images
99296 wrap = wrap.merge(wrapEnter).call(setupCanvas, true); // Register viewer resize handler
99298 context.ui().photoviewer.on('resize.streetside', function () {
99299 if (_pannellumViewer) {
99300 _pannellumViewer.resize();
99303 _loadViewerPromise = new Promise(function (resolve, reject) {
99304 var loadedCount = 0;
99306 function loaded() {
99307 loadedCount += 1; // wait until both files are loaded
99309 if (loadedCount === 2) resolve();
99312 var head = select('head'); // load streetside pannellum viewer css
99314 head.selectAll('#ideditor-streetside-viewercss').data([0]).enter().append('link').attr('id', 'ideditor-streetside-viewercss').attr('rel', 'stylesheet').attr('crossorigin', 'anonymous').attr('href', context.asset(pannellumViewerCSS)).on('load.serviceStreetside', loaded).on('error.serviceStreetside', function () {
99316 }); // load streetside pannellum viewer js
99318 head.selectAll('#ideditor-streetside-viewerjs').data([0]).enter().append('script').attr('id', 'ideditor-streetside-viewerjs').attr('crossorigin', 'anonymous').attr('src', context.asset(pannellumViewerJS)).on('load.serviceStreetside', loaded).on('error.serviceStreetside', function () {
99321 })["catch"](function () {
99322 _loadViewerPromise = null;
99324 return _loadViewerPromise;
99326 function step(stepBy) {
99327 return function () {
99328 var viewer = context.container().select('.photoviewer');
99329 var selected = viewer.empty() ? undefined : viewer.datum();
99330 if (!selected) return;
99331 var nextID = stepBy === 1 ? selected.ne : selected.pr;
99333 var yaw = _pannellumViewer.getYaw();
99335 var ca = selected.ca + yaw;
99336 var origin = selected.loc; // construct a search trapezoid pointing out from current bubble
99339 var p1 = [origin[0] + geoMetersToLon(meters / 5, origin[1]), origin[1]];
99340 var p2 = [origin[0] + geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
99341 var p3 = [origin[0] - geoMetersToLon(meters / 2, origin[1]), origin[1] + geoMetersToLat(meters)];
99342 var p4 = [origin[0] - geoMetersToLon(meters / 5, origin[1]), origin[1]];
99343 var poly = [p1, p2, p3, p4, p1]; // rotate it to face forward/backward
99345 var angle = (stepBy === 1 ? ca : ca + 180) * (Math.PI / 180);
99346 poly = geoRotate(poly, -angle, origin);
99347 var extent = poly.reduce(function (extent, point) {
99348 return extent.extend(geoExtent(point));
99349 }, geoExtent()); // find nearest other bubble in the search polygon
99351 var minDist = Infinity;
99353 _ssCache.bubbles.rtree.search(extent.bbox()).forEach(function (d) {
99354 if (d.data.key === selected.key) return;
99355 if (!geoPointInPolygon(d.data.loc, poly)) return;
99356 var dist = geoVecLength(d.data.loc, selected.loc);
99357 var theta = selected.ca - d.data.ca;
99358 var minTheta = Math.min(Math.abs(theta), 360 - Math.abs(theta));
99360 if (minTheta > 20) {
99361 dist += 5; // penalize distance if camera angles don't match
99364 if (dist < minDist) {
99365 nextID = d.data.key;
99370 var nextBubble = nextID && that.cachedImage(nextID);
99371 if (!nextBubble) return;
99372 context.map().centerEase(nextBubble.loc);
99373 that.selectImage(context, nextBubble.key).yaw(yaw).showViewer(context);
99377 yaw: function yaw(_yaw) {
99378 if (typeof _yaw !== 'number') return _yaw;
99379 _sceneOptions.yaw = _yaw;
99386 showViewer: function showViewer(context) {
99387 var wrap = context.container().select('.photoviewer').classed('hide', false);
99388 var isHidden = wrap.selectAll('.photo-wrapper.ms-wrapper.hide').size();
99391 wrap.selectAll('.photo-wrapper:not(.ms-wrapper)').classed('hide', true);
99392 wrap.selectAll('.photo-wrapper.ms-wrapper').classed('hide', false);
99401 hideViewer: function hideViewer(context) {
99402 var viewer = context.container().select('.photoviewer');
99403 if (!viewer.empty()) viewer.datum(null);
99404 viewer.classed('hide', true).selectAll('.photo-wrapper').classed('hide', true);
99405 context.container().selectAll('.viewfield-group, .sequence, .icon-sign').classed('currentView', false);
99406 this.updateUrlImage(null);
99407 return this.setStyles(context, null, true);
99413 selectImage: function selectImage(context, key) {
99415 var d = this.cachedImage(key);
99416 var viewer = context.container().select('.photoviewer');
99417 if (!viewer.empty()) viewer.datum(d);
99418 this.setStyles(context, null, true);
99419 var wrap = context.container().select('.photoviewer .ms-wrapper');
99420 var attribution = wrap.selectAll('.photo-attribution').html('');
99421 wrap.selectAll('.pnlm-load-box') // display "loading.."
99422 .style('display', 'block');
99423 if (!d) return this;
99424 this.updateUrlImage(key);
99425 _sceneOptions.northOffset = d.ca;
99426 var line1 = attribution.append('div').attr('class', 'attribution-row');
99427 var hiresDomId = utilUniqueDomId('streetside-hires'); // Add hires checkbox
99429 var label = line1.append('label').attr('for', hiresDomId).attr('class', 'streetside-hires');
99430 label.append('input').attr('type', 'checkbox').attr('id', hiresDomId).property('checked', _hires).on('click', function (d3_event) {
99431 d3_event.stopPropagation();
99433 _resolution = _hires ? 1024 : 512;
99434 wrap.call(setupCanvas, true);
99436 yaw: _pannellumViewer.getYaw(),
99437 pitch: _pannellumViewer.getPitch(),
99438 hfov: _pannellumViewer.getHfov()
99440 _sceneOptions = Object.assign(_sceneOptions, viewstate);
99441 that.selectImage(context, d.key).showViewer(context);
99443 label.append('span').html(_t.html('streetside.hires'));
99444 var captureInfo = line1.append('div').attr('class', 'attribution-capture-info'); // Add capture date
99446 if (d.captured_by) {
99447 var yyyy = new Date().getFullYear();
99448 captureInfo.append('a').attr('class', 'captured_by').attr('target', '_blank').attr('href', 'https://www.microsoft.com/en-us/maps/streetside').html('©' + yyyy + ' Microsoft');
99449 captureInfo.append('span').html('|');
99452 if (d.captured_at) {
99453 captureInfo.append('span').attr('class', 'captured_at').html(localeTimestamp(d.captured_at));
99454 } // Add image links
99457 var line2 = attribution.append('div').attr('class', 'attribution-row');
99458 line2.append('a').attr('class', 'image-view-link').attr('target', '_blank').attr('href', 'https://www.bing.com/maps?cp=' + d.loc[1] + '~' + d.loc[0] + '&lvl=17&dir=' + d.ca + '&style=x&v=2&sV=1').html(_t.html('streetside.view_on_bing'));
99459 line2.append('a').attr('class', 'image-report-link').attr('target', '_blank').attr('href', 'https://www.bing.com/maps/privacyreport/streetsideprivacyreport?bubbleid=' + encodeURIComponent(d.key) + '&focus=photo&lat=' + d.loc[1] + '&lng=' + d.loc[0] + '&z=17').html(_t.html('streetside.report'));
99460 var bubbleIdQuadKey = d.key.toString(4);
99461 var paddingNeeded = 16 - bubbleIdQuadKey.length;
99463 for (var i = 0; i < paddingNeeded; i++) {
99464 bubbleIdQuadKey = '0' + bubbleIdQuadKey;
99467 var imgUrlPrefix = streetsideImagesApi + 'hs' + bubbleIdQuadKey;
99468 var imgUrlSuffix = '.jpg?g=6338&n=z'; // Cubemap face code order matters here: front=01, right=02, back=03, left=10, up=11, down=12
99470 var faceKeys = ['01', '02', '03', '10', '11', '12']; // Map images to cube faces
99472 var quadKeys = getQuadKeys();
99473 var faces = faceKeys.map(function (faceKey) {
99474 return quadKeys.map(function (quadKey) {
99475 var xy = qkToXY(quadKey);
99478 url: imgUrlPrefix + faceKey + quadKey + imgUrlSuffix,
99484 loadFaces(faces).then(function () {
99485 if (!_pannellumViewer) {
99488 // make a new scene
99491 var sceneID = _currScene.toString();
99493 _pannellumViewer.addScene(sceneID, _sceneOptions).loadScene(sceneID); // remove previous scene
99496 if (_currScene > 2) {
99497 sceneID = (_currScene - 1).toString();
99499 _pannellumViewer.removeScene(sceneID);
99505 getSequenceKeyForBubble: function getSequenceKeyForBubble(d) {
99506 return d && d.sequenceKey;
99508 // Updates the currently highlighted sequence and selected bubble.
99509 // Reset is only necessary when interacting with the viewport because
99510 // this implicitly changes the currently selected bubble/sequence
99511 setStyles: function setStyles(context, hovered, reset) {
99513 // reset all layers
99514 context.container().selectAll('.viewfield-group').classed('highlighted', false).classed('hovered', false).classed('currentView', false);
99515 context.container().selectAll('.sequence').classed('highlighted', false).classed('currentView', false);
99518 var hoveredBubbleKey = hovered && hovered.key;
99519 var hoveredSequenceKey = this.getSequenceKeyForBubble(hovered);
99520 var hoveredSequence = hoveredSequenceKey && _ssCache.sequences[hoveredSequenceKey];
99521 var hoveredBubbleKeys = hoveredSequence && hoveredSequence.bubbles.map(function (d) {
99524 var viewer = context.container().select('.photoviewer');
99525 var selected = viewer.empty() ? undefined : viewer.datum();
99526 var selectedBubbleKey = selected && selected.key;
99527 var selectedSequenceKey = this.getSequenceKeyForBubble(selected);
99528 var selectedSequence = selectedSequenceKey && _ssCache.sequences[selectedSequenceKey];
99529 var selectedBubbleKeys = selectedSequence && selectedSequence.bubbles.map(function (d) {
99531 }) || []; // highlight sibling viewfields on either the selected or the hovered sequences
99533 var highlightedBubbleKeys = utilArrayUnion(hoveredBubbleKeys, selectedBubbleKeys);
99534 context.container().selectAll('.layer-streetside-images .viewfield-group').classed('highlighted', function (d) {
99535 return highlightedBubbleKeys.indexOf(d.key) !== -1;
99536 }).classed('hovered', function (d) {
99537 return d.key === hoveredBubbleKey;
99538 }).classed('currentView', function (d) {
99539 return d.key === selectedBubbleKey;
99541 context.container().selectAll('.layer-streetside-images .sequence').classed('highlighted', function (d) {
99542 return d.properties.key === hoveredSequenceKey;
99543 }).classed('currentView', function (d) {
99544 return d.properties.key === selectedSequenceKey;
99545 }); // update viewfields if needed
99547 context.container().selectAll('.layer-streetside-images .viewfield-group .viewfield').attr('d', viewfieldPath);
99549 function viewfieldPath() {
99550 var d = this.parentNode.__data__;
99552 if (d.pano && d.key !== selectedBubbleKey) {
99553 return 'M 8,13 m -10,0 a 10,10 0 1,0 20,0 a 10,10 0 1,0 -20,0';
99555 return 'M 6,9 C 8,8.4 8,8.4 10,9 L 16,-2 C 12,-5 4,-5 0,-2 z';
99561 updateUrlImage: function updateUrlImage(imageKey) {
99562 if (!window.mocha) {
99563 var hash = utilStringQs(window.location.hash);
99566 hash.photo = 'streetside/' + imageKey;
99571 window.location.replace('#' + utilQsString(hash, true));
99578 cache: function cache() {
99583 var _apibase = 'https://taginfo.openstreetmap.org/api/4/';
99584 var _inflight = {};
99585 var _popularKeys = {};
99586 var _taginfoCache = {};
99588 point: 'count_nodes',
99589 vertex: 'count_nodes',
99590 area: 'count_ways',
99593 var tag_sort_members = {
99594 point: 'count_node_members',
99595 vertex: 'count_node_members',
99596 area: 'count_way_members',
99597 line: 'count_way_members',
99598 relation: 'count_relation_members'
99600 var tag_filters = {
99606 var tag_members_fractions = {
99607 point: 'count_node_members_fraction',
99608 vertex: 'count_node_members_fraction',
99609 area: 'count_way_members_fraction',
99610 line: 'count_way_members_fraction',
99611 relation: 'count_relation_members_fraction'
99614 function sets(params, n, o) {
99615 if (params.geometry && o[params.geometry]) {
99616 params[n] = o[params.geometry];
99622 function setFilter(params) {
99623 return sets(params, 'filter', tag_filters);
99626 function setSort(params) {
99627 return sets(params, 'sortname', tag_sorts);
99630 function setSortMembers(params) {
99631 return sets(params, 'sortname', tag_sort_members);
99634 function clean(params) {
99635 return utilObjectOmit(params, ['geometry', 'debounce']);
99638 function filterKeys(type) {
99639 var count_type = type ? 'count_' + type : 'count_all';
99640 return function (d) {
99641 return parseFloat(d[count_type]) > 2500 || d.in_wiki;
99645 function filterMultikeys(prefix) {
99646 return function (d) {
99647 // d.key begins with prefix, and d.key contains no additional ':'s
99648 var re = new RegExp('^' + prefix + '(.*)$');
99649 var matches = d.key.match(re) || [];
99650 return matches.length === 2 && matches[1].indexOf(':') === -1;
99654 function filterValues(allowUpperCase) {
99655 return function (d) {
99656 if (d.value.match(/[;,]/) !== null) return false; // exclude some punctuation
99658 if (!allowUpperCase && d.value.match(/[A-Z*]/) !== null) return false; // exclude uppercase letters
99660 return parseFloat(d.fraction) > 0.0;
99664 function filterRoles(geometry) {
99665 return function (d) {
99666 if (d.role === '') return false; // exclude empty role
99668 if (d.role.match(/[A-Z*;,]/) !== null) return false; // exclude uppercase letters and some punctuation
99670 return parseFloat(d[tag_members_fractions[geometry]]) > 0.0;
99674 function valKey(d) {
99681 function valKeyDescription(d) {
99684 title: d.description || d.value
99688 obj.count = d.count;
99694 function roleKey(d) {
99699 } // sort keys with ':' lower than keys without ':'
99702 function sortKeys(a, b) {
99703 return a.key.indexOf(':') === -1 && b.key.indexOf(':') !== -1 ? -1 : a.key.indexOf(':') !== -1 && b.key.indexOf(':') === -1 ? 1 : 0;
99706 var debouncedRequest = debounce(request, 300, {
99710 function request(url, params, exactMatch, callback, loaded) {
99711 if (_inflight[url]) return;
99712 if (checkCache(url, params, exactMatch, callback)) return;
99713 var controller = new AbortController();
99714 _inflight[url] = controller;
99716 signal: controller.signal
99717 }).then(function (result) {
99718 delete _inflight[url];
99719 if (loaded) loaded(null, result);
99720 })["catch"](function (err) {
99721 delete _inflight[url];
99722 if (err.name === 'AbortError') return;
99723 if (loaded) loaded(err.message);
99727 function checkCache(url, params, exactMatch, callback) {
99728 var rp = params.rp || 25;
99729 var testQuery = params.query || '';
99733 var hit = _taginfoCache[testUrl]; // exact match, or shorter match yielding fewer than max results (rp)
99735 if (hit && (url === testUrl || hit.length < rp)) {
99736 callback(null, hit);
99738 } // don't try to shorten the query
99741 if (exactMatch || !testQuery.length) return false; // do shorten the query to see if we already have a cached result
99742 // that has returned fewer than max results (rp)
99744 testQuery = testQuery.slice(0, -1);
99745 testUrl = url.replace(/&query=(.*?)&/, '&query=' + testQuery + '&');
99746 } while (testQuery.length >= 0);
99751 var serviceTaginfo = {
99752 init: function init() {
99754 _taginfoCache = {};
99756 // manually exclude some keys – #5377, #7485
99762 sorting_name: true,
99766 'bridge:name': true
99767 }; // Fetch popular keys. We'll exclude these from `values`
99768 // lookups because they stress taginfo, and they aren't likely
99769 // to yield meaningful autocomplete results.. see #3955
99773 sortname: 'values_all',
99777 lang: _mainLocalizer.languageCode()
99779 this.keys(params, function (err, data) {
99781 data.forEach(function (d) {
99782 if (d.value === 'opening_hours') return; // exception
99784 _popularKeys[d.value] = true;
99788 reset: function reset() {
99789 Object.values(_inflight).forEach(function (controller) {
99790 controller.abort();
99794 keys: function keys(params, callback) {
99795 var doRequest = params.debounce ? debouncedRequest : request;
99796 params = clean(setSort(params));
99797 params = Object.assign({
99799 sortname: 'count_all',
99802 lang: _mainLocalizer.languageCode()
99804 var url = _apibase + 'keys/all?' + utilQsString(params);
99805 doRequest(url, params, false, callback, function (err, d) {
99809 var f = filterKeys(params.filter);
99810 var result = d.data.filter(f).sort(sortKeys).map(valKey);
99811 _taginfoCache[url] = result;
99812 callback(null, result);
99816 multikeys: function multikeys(params, callback) {
99817 var doRequest = params.debounce ? debouncedRequest : request;
99818 params = clean(setSort(params));
99819 params = Object.assign({
99821 sortname: 'count_all',
99824 lang: _mainLocalizer.languageCode()
99826 var prefix = params.query;
99827 var url = _apibase + 'keys/all?' + utilQsString(params);
99828 doRequest(url, params, true, callback, function (err, d) {
99832 var f = filterMultikeys(prefix);
99833 var result = d.data.filter(f).map(valKey);
99834 _taginfoCache[url] = result;
99835 callback(null, result);
99839 values: function values(params, callback) {
99840 // Exclude popular keys from values lookups.. see #3955
99841 var key = params.key;
99843 if (key && _popularKeys[key]) {
99844 callback(null, []);
99848 var doRequest = params.debounce ? debouncedRequest : request;
99849 params = clean(setSort(setFilter(params)));
99850 params = Object.assign({
99852 sortname: 'count_all',
99855 lang: _mainLocalizer.languageCode()
99857 var url = _apibase + 'key/values?' + utilQsString(params);
99858 doRequest(url, params, false, callback, function (err, d) {
99862 // In most cases we prefer taginfo value results with lowercase letters.
99863 // A few OSM keys expect values to contain uppercase values (see #3377).
99864 // This is not an exhaustive list (e.g. `name` also has uppercase values)
99865 // but these are the fields where taginfo value lookup is most useful.
99866 var re = /network|taxon|genus|species|brand|grape_variety|royal_cypher|listed_status|booth|rating|stars|:output|_hours|_times|_ref|manufacturer|country|target|brewery/;
99867 var allowUpperCase = re.test(params.key);
99868 var f = filterValues(allowUpperCase);
99869 var result = d.data.filter(f).map(valKeyDescription);
99870 _taginfoCache[url] = result;
99871 callback(null, result);
99875 roles: function roles(params, callback) {
99876 var doRequest = params.debounce ? debouncedRequest : request;
99877 var geometry = params.geometry;
99878 params = clean(setSortMembers(params));
99879 params = Object.assign({
99881 sortname: 'count_all_members',
99884 lang: _mainLocalizer.languageCode()
99886 var url = _apibase + 'relation/roles?' + utilQsString(params);
99887 doRequest(url, params, true, callback, function (err, d) {
99891 var f = filterRoles(geometry);
99892 var result = d.data.filter(f).map(roleKey);
99893 _taginfoCache[url] = result;
99894 callback(null, result);
99898 docs: function docs(params, callback) {
99899 var doRequest = params.debounce ? debouncedRequest : request;
99900 params = clean(setSort(params));
99901 var path = 'key/wiki_pages?';
99903 if (params.value) {
99904 path = 'tag/wiki_pages?';
99905 } else if (params.rtype) {
99906 path = 'relation/wiki_pages?';
99909 var url = _apibase + path + utilQsString(params);
99910 doRequest(url, params, true, callback, function (err, d) {
99914 _taginfoCache[url] = d.data;
99915 callback(null, d.data);
99919 apibase: function apibase(_) {
99920 if (!arguments.length) return _apibase;
99927 * Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}.
99930 * @param {Geometry} geometry input geometry
99931 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
99932 * @param {Object} [options={}] Optional Parameters
99933 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
99934 * @param {string|number} [options.id] Identifier associated with the Feature
99935 * @returns {Feature} a GeoJSON Feature
99939 * "coordinates": [110, 50]
99942 * var feature = turf.feature(geometry);
99947 function feature(geom, properties, options) {
99948 if (options === void 0) {
99956 if (options.id === 0 || options.id) {
99957 feat.id = options.id;
99960 if (options.bbox) {
99961 feat.bbox = options.bbox;
99964 feat.properties = properties || {};
99965 feat.geometry = geom;
99969 * Creates a {@link Polygon} {@link Feature} from an Array of LinearRings.
99972 * @param {Array<Array<Array<number>>>} coordinates an array of LinearRings
99973 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
99974 * @param {Object} [options={}] Optional Parameters
99975 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
99976 * @param {string|number} [options.id] Identifier associated with the Feature
99977 * @returns {Feature<Polygon>} Polygon Feature
99979 * var polygon = turf.polygon([[[-5, 52], [-4, 56], [-2, 51], [-7, 54], [-5, 52]]], { name: 'poly1' });
99984 function polygon(coordinates, properties, options) {
99985 if (options === void 0) {
99989 for (var _i = 0, coordinates_1 = coordinates; _i < coordinates_1.length; _i++) {
99990 var ring = coordinates_1[_i];
99992 if (ring.length < 4) {
99993 throw new Error("Each LinearRing of a Polygon must have 4 or more Positions.");
99996 for (var j = 0; j < ring[ring.length - 1].length; j++) {
99997 // Check if first point of Polygon contains two numbers
99998 if (ring[ring.length - 1][j] !== ring[0][j]) {
99999 throw new Error("First and last Position are not equivalent.");
100006 coordinates: coordinates
100008 return feature(geom, properties, options);
100011 * Creates a {@link LineString} {@link Feature} from an Array of Positions.
100014 * @param {Array<Array<number>>} coordinates an array of Positions
100015 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100016 * @param {Object} [options={}] Optional Parameters
100017 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100018 * @param {string|number} [options.id] Identifier associated with the Feature
100019 * @returns {Feature<LineString>} LineString Feature
100021 * var linestring1 = turf.lineString([[-24, 63], [-23, 60], [-25, 65], [-20, 69]], {name: 'line 1'});
100022 * var linestring2 = turf.lineString([[-14, 43], [-13, 40], [-15, 45], [-10, 49]], {name: 'line 2'});
100028 function lineString(coordinates, properties, options) {
100029 if (options === void 0) {
100033 if (coordinates.length < 2) {
100034 throw new Error("coordinates must be an array of two or more positions");
100039 coordinates: coordinates
100041 return feature(geom, properties, options);
100044 * Creates a {@link Feature<MultiLineString>} based on a
100045 * coordinate array. Properties can be added optionally.
100047 * @name multiLineString
100048 * @param {Array<Array<Array<number>>>} coordinates an array of LineStrings
100049 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100050 * @param {Object} [options={}] Optional Parameters
100051 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100052 * @param {string|number} [options.id] Identifier associated with the Feature
100053 * @returns {Feature<MultiLineString>} a MultiLineString feature
100054 * @throws {Error} if no coordinates are passed
100056 * var multiLine = turf.multiLineString([[[0,0],[10,10]]]);
100061 function multiLineString(coordinates, properties, options) {
100062 if (options === void 0) {
100067 type: "MultiLineString",
100068 coordinates: coordinates
100070 return feature(geom, properties, options);
100073 * Creates a {@link Feature<MultiPolygon>} based on a
100074 * coordinate array. Properties can be added optionally.
100077 * @param {Array<Array<Array<Array<number>>>>} coordinates an array of Polygons
100078 * @param {Object} [properties={}] an Object of key-value pairs to add as properties
100079 * @param {Object} [options={}] Optional Parameters
100080 * @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature
100081 * @param {string|number} [options.id] Identifier associated with the Feature
100082 * @returns {Feature<MultiPolygon>} a multipolygon feature
100083 * @throws {Error} if no coordinates are passed
100085 * var multiPoly = turf.multiPolygon([[[[0,0],[0,10],[10,10],[10,0],[0,0]]]]);
100091 function multiPolygon(coordinates, properties, options) {
100092 if (options === void 0) {
100098 coordinates: coordinates
100100 return feature(geom, properties, options);
100104 * Get Geometry from Feature or Geometry Object
100106 * @param {Feature|Geometry} geojson GeoJSON Feature or Geometry Object
100107 * @returns {Geometry|null} GeoJSON Geometry Object
100108 * @throws {Error} if geojson is not a Feature or Geometry Object
100115 * "coordinates": [110, 40]
100118 * var geom = turf.getGeom(point)
100119 * //={"type": "Point", "coordinates": [110, 40]}
100122 function getGeom(geojson) {
100123 if (geojson.type === "Feature") {
100124 return geojson.geometry;
100130 // Cohen-Sutherland line clipping algorithm, adapted to efficiently
100131 // handle polylines rather than just segments
100132 function lineclip(points, bbox, result) {
100133 var len = points.length,
100134 codeA = bitCode(points[0], bbox),
100141 if (!result) result = [];
100143 for (i = 1; i < len; i++) {
100146 codeB = lastCode = bitCode(b, bbox);
100149 if (!(codeA | codeB)) {
100153 if (codeB !== lastCode) {
100154 // segment went outside
100162 } else if (i === len - 1) {
100167 } else if (codeA & codeB) {
100171 // a outside, intersect with clip edge
100172 a = intersect(a, b, codeA, bbox);
100173 codeA = bitCode(a, bbox);
100176 b = intersect(a, b, codeB, bbox);
100177 codeB = bitCode(b, bbox);
100184 if (part.length) result.push(part);
100186 } // Sutherland-Hodgeman polygon clipping algorithm
100188 function polygonclip(points, bbox) {
100189 var result, edge, prev, prevInside, i, p, inside; // clip against each side of the clip rectangle
100191 for (edge = 1; edge <= 8; edge *= 2) {
100193 prev = points[points.length - 1];
100194 prevInside = !(bitCode(prev, bbox) & edge);
100196 for (i = 0; i < points.length; i++) {
100198 inside = !(bitCode(p, bbox) & edge); // if segment goes through the clip window, add an intersection
100200 if (inside !== prevInside) result.push(intersect(prev, p, edge, bbox));
100201 if (inside) result.push(p); // add a point if it's inside
100208 if (!points.length) break;
100212 } // intersect a segment against one of the 4 lines that make up the bbox
100214 function intersect(a, b, edge, bbox) {
100215 return edge & 8 ? [a[0] + (b[0] - a[0]) * (bbox[3] - a[1]) / (b[1] - a[1]), bbox[3]] // top
100216 : edge & 4 ? [a[0] + (b[0] - a[0]) * (bbox[1] - a[1]) / (b[1] - a[1]), bbox[1]] // bottom
100217 : edge & 2 ? [bbox[2], a[1] + (b[1] - a[1]) * (bbox[2] - a[0]) / (b[0] - a[0])] // right
100218 : edge & 1 ? [bbox[0], a[1] + (b[1] - a[1]) * (bbox[0] - a[0]) / (b[0] - a[0])] // left
100220 } // bit code reflects the point position relative to the bbox:
100224 // bottom 0101 0100 0110
100227 function bitCode(p, bbox) {
100229 if (p[0] < bbox[0]) code |= 1; // left
100230 else if (p[0] > bbox[2]) code |= 2; // right
100232 if (p[1] < bbox[1]) code |= 4; // bottom
100233 else if (p[1] > bbox[3]) code |= 8; // top
100239 * Takes a {@link Feature} and a bbox and clips the feature to the bbox using
100240 * [lineclip](https://github.com/mapbox/lineclip).
100241 * May result in degenerate edges when clipping Polygons.
100244 * @param {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} feature feature to clip to the bbox
100245 * @param {BBox} bbox extent in [minX, minY, maxX, maxY] order
100246 * @returns {Feature<LineString|MultiLineString|Polygon|MultiPolygon>} clipped Feature
100248 * var bbox = [0, 0, 10, 10];
100249 * var poly = turf.polygon([[[2, 2], [8, 4], [12, 8], [3, 7], [2, 2]]]);
100251 * var clipped = turf.bboxClip(poly, bbox);
100254 * var addToMap = [bbox, poly, clipped]
100257 function bboxClip(feature, bbox) {
100258 var geom = getGeom(feature);
100260 var properties = feature.type === "Feature" ? feature.properties : {};
100261 var coords = geom.coordinates;
100265 case "MultiLineString":
100268 if (type === "LineString") {
100272 coords.forEach(function (line) {
100273 lineclip(line, bbox, lines_1);
100276 if (lines_1.length === 1) {
100277 return lineString(lines_1[0], properties);
100280 return multiLineString(lines_1, properties);
100283 return polygon(clipPolygon(coords, bbox), properties);
100286 return multiPolygon(coords.map(function (poly) {
100287 return clipPolygon(poly, bbox);
100291 throw new Error("geometry " + type + " not supported");
100295 function clipPolygon(rings, bbox) {
100298 for (var _i = 0, rings_1 = rings; _i < rings_1.length; _i++) {
100299 var ring = rings_1[_i];
100300 var clipped = polygonclip(ring, bbox);
100302 if (clipped.length > 0) {
100303 if (clipped[0][0] !== clipped[clipped.length - 1][0] || clipped[0][1] !== clipped[clipped.length - 1][1]) {
100304 clipped.push(clipped[0]);
100307 if (clipped.length >= 4) {
100308 outRings.push(clipped);
100316 var tiler = utilTiler().tileSize(512).margin(1);
100317 var dispatch = dispatch$8('loadedData');
100321 function abortRequest(controller) {
100325 function vtToGeoJSON(data, tile, mergeCache) {
100326 var vectorTile$1 = new vectorTile.VectorTile(new pbf(data));
100327 var layers = Object.keys(vectorTile$1.layers);
100329 if (!Array.isArray(layers)) {
100334 layers.forEach(function (layerID) {
100335 var layer = vectorTile$1.layers[layerID];
100338 for (var i = 0; i < layer.length; i++) {
100339 var feature = layer.feature(i).toGeoJSON(tile.xyz[0], tile.xyz[1], tile.xyz[2]);
100340 var geometry = feature.geometry; // Treat all Polygons as MultiPolygons
100342 if (geometry.type === 'Polygon') {
100343 geometry.type = 'MultiPolygon';
100344 geometry.coordinates = [geometry.coordinates];
100347 var isClipped = false; // Clip to tile bounds
100349 if (geometry.type === 'MultiPolygon') {
100350 var featureClip = bboxClip(feature, tile.extent.rectangle());
100352 if (!fastDeepEqual(feature.geometry, featureClip.geometry)) {
100353 // feature = featureClip;
100357 if (!feature.geometry.coordinates.length) continue; // not actually on this tile
100359 if (!feature.geometry.coordinates[0].length) continue; // not actually on this tile
100360 } // Generate some unique IDs and add some metadata
100363 var featurehash = utilHashcode(fastJsonStableStringify(feature));
100364 var propertyhash = utilHashcode(fastJsonStableStringify(feature.properties || {}));
100365 feature.__layerID__ = layerID.replace(/[^_a-zA-Z0-9\-]/g, '_');
100366 feature.__featurehash__ = featurehash;
100367 feature.__propertyhash__ = propertyhash;
100368 features.push(feature); // Clipped Polygons at same zoom with identical properties can get merged
100370 if (isClipped && geometry.type === 'MultiPolygon') {
100371 var merged = mergeCache[propertyhash];
100373 if (merged && merged.length) {
100375 var coords = index.union(feature.geometry.coordinates, other.geometry.coordinates);
100377 if (!coords || !coords.length) {
100378 continue; // something failed in polygon union
100383 for (var j = 0; j < merged.length; j++) {
100384 // all these features get...
100385 merged[j].geometry.coordinates = coords; // same coords
100387 merged[j].__featurehash__ = featurehash; // same hash, so deduplication works
100390 mergeCache[propertyhash] = [feature];
100399 function loadTile(source, tile) {
100400 if (source.loaded[tile.id] || source.inflight[tile.id]) return;
100401 var url = source.template.replace('{x}', tile.xyz[0]).replace('{y}', tile.xyz[1]) // TMS-flipped y coordinate
100402 .replace(/\{[t-]y\}/, Math.pow(2, tile.xyz[2]) - tile.xyz[1] - 1).replace(/\{z(oom)?\}/, tile.xyz[2]).replace(/\{switch:([^}]+)\}/, function (s, r) {
100403 var subdomains = r.split(',');
100404 return subdomains[(tile.xyz[0] + tile.xyz[1]) % subdomains.length];
100406 var controller = new AbortController();
100407 source.inflight[tile.id] = controller;
100409 signal: controller.signal
100410 }).then(function (response) {
100412 throw new Error(response.status + ' ' + response.statusText);
100415 source.loaded[tile.id] = [];
100416 delete source.inflight[tile.id];
100417 return response.arrayBuffer();
100418 }).then(function (data) {
100420 throw new Error('No Data');
100425 if (!source.canMerge[z]) {
100426 source.canMerge[z] = {}; // initialize mergeCache
100429 source.loaded[tile.id] = vtToGeoJSON(data, tile, source.canMerge[z]);
100430 dispatch.call('loadedData');
100431 })["catch"](function () {
100432 source.loaded[tile.id] = [];
100433 delete source.inflight[tile.id];
100437 var serviceVectorTile = {
100438 init: function init() {
100443 this.event = utilRebind(this, dispatch, 'on');
100445 reset: function reset() {
100446 for (var sourceID in _vtCache) {
100447 var source = _vtCache[sourceID];
100449 if (source && source.inflight) {
100450 Object.values(source.inflight).forEach(abortRequest);
100456 addSource: function addSource(sourceID, template) {
100463 return _vtCache[sourceID];
100465 data: function data(sourceID, projection) {
100466 var source = _vtCache[sourceID];
100467 if (!source) return [];
100468 var tiles = tiler.getTiles(projection);
100472 for (var i = 0; i < tiles.length; i++) {
100473 var features = source.loaded[tiles[i].id];
100474 if (!features || !features.length) continue;
100476 for (var j = 0; j < features.length; j++) {
100477 var feature = features[j];
100478 var hash = feature.__featurehash__;
100479 if (seen[hash]) continue;
100480 seen[hash] = true; // return a shallow copy, because the hash may change
100481 // later if this feature gets merged with another
100483 results.push(Object.assign({}, feature)); // shallow copy
100489 loadTiles: function loadTiles(sourceID, template, projection) {
100490 var source = _vtCache[sourceID];
100493 source = this.addSource(sourceID, template);
100496 var tiles = tiler.getTiles(projection); // abort inflight requests that are no longer needed
100498 Object.keys(source.inflight).forEach(function (k) {
100499 var wanted = tiles.find(function (tile) {
100504 abortRequest(source.inflight[k]);
100505 delete source.inflight[k];
100508 tiles.forEach(function (tile) {
100509 loadTile(source, tile);
100512 cache: function cache() {
100517 var apibase = 'https://www.wikidata.org/w/api.php?';
100518 var _wikidataCache = {};
100519 var serviceWikidata = {
100520 init: function init() {},
100521 reset: function reset() {
100524 // Search for Wikidata items matching the query
100525 itemsForSearchQuery: function itemsForSearchQuery(query, callback) {
100527 if (callback) callback('No query', {});
100531 var lang = this.languagesToQuery()[0];
100532 var url = apibase + utilQsString({
100533 action: 'wbsearchentities',
100538 // the language to search
100540 // the language for the label and description in the result
100545 d3_json(url).then(function (result) {
100546 if (result && result.error) {
100547 throw new Error(result.error);
100550 if (callback) callback(null, result.search || {});
100551 })["catch"](function (err) {
100552 if (callback) callback(err.message, {});
100555 // Given a Wikipedia language and article title,
100556 // return an array of corresponding Wikidata entities.
100557 itemsByTitle: function itemsByTitle(lang, title, callback) {
100559 if (callback) callback('No title', {});
100564 var url = apibase + utilQsString({
100565 action: 'wbgetentities',
100568 sites: lang.replace(/-/g, '_') + 'wiki',
100571 // shrink response by filtering to one language
100574 d3_json(url).then(function (result) {
100575 if (result && result.error) {
100576 throw new Error(result.error);
100579 if (callback) callback(null, result.entities || {});
100580 })["catch"](function (err) {
100581 if (callback) callback(err.message, {});
100584 languagesToQuery: function languagesToQuery() {
100585 return _mainLocalizer.localeCodes().map(function (code) {
100586 return code.toLowerCase();
100587 }).filter(function (code) {
100588 // HACK: en-us isn't a wikidata language. We should really be filtering by
100589 // the languages known to be supported by wikidata.
100590 return code !== 'en-us';
100593 entityByQID: function entityByQID(qid, callback) {
100595 callback('No qid', {});
100599 if (_wikidataCache[qid]) {
100600 if (callback) callback(null, _wikidataCache[qid]);
100604 var langs = this.languagesToQuery();
100605 var url = apibase + utilQsString({
100606 action: 'wbgetentities',
100610 props: 'labels|descriptions|claims|sitelinks',
100611 sitefilter: langs.map(function (d) {
100614 languages: langs.join('|'),
100618 d3_json(url).then(function (result) {
100619 if (result && result.error) {
100620 throw new Error(result.error);
100623 if (callback) callback(null, result.entities[qid] || {});
100624 })["catch"](function (err) {
100625 if (callback) callback(err.message, {});
100628 // Pass `params` object of the form:
100630 // qid: 'string' // brand wikidata (e.g. 'Q37158')
100633 // Get an result object used to display tag documentation
100636 // description: 'string',
100639 // wiki: { title: 'string', text: 'string', url: 'string' }
100642 getDocs: function getDocs(params, callback) {
100643 var langs = this.languagesToQuery();
100644 this.entityByQID(params.qid, function (err, entity) {
100646 callback(err || 'No entity');
100656 if (entity.descriptions[code] && entity.descriptions[code].language === code) {
100657 description = entity.descriptions[code];
100662 if (!description && Object.values(entity.descriptions).length) description = Object.values(entity.descriptions)[0]; // prepare result
100666 description: description ? description.value : '',
100667 descriptionLocaleCode: description ? description.language : '',
100668 editURL: 'https://www.wikidata.org/wiki/' + entity.id
100672 var imageroot = 'https://commons.wikimedia.org/w/index.php';
100673 var props = ['P154', 'P18']; // logo image, image
100677 for (i = 0; i < props.length; i++) {
100678 prop = entity.claims[props[i]];
100680 if (prop && Object.keys(prop).length > 0) {
100681 image = prop[Object.keys(prop)[0]].mainsnak.datavalue.value;
100684 result.imageURL = imageroot + '?' + utilQsString({
100685 title: 'Special:Redirect/file/' + image,
100694 if (entity.sitelinks) {
100695 var englishLocale = _mainLocalizer.languageCode().toLowerCase() === 'en'; // must be one of these that we requested..
100697 for (i = 0; i < langs.length; i++) {
100698 // check each, in order of preference
100699 var w = langs[i] + 'wiki';
100701 if (entity.sitelinks[w]) {
100702 var title = entity.sitelinks[w].title;
100703 var tKey = 'inspector.wiki_reference';
100705 if (!englishLocale && langs[i] === 'en') {
100706 // user's locale isn't English but
100707 tKey = 'inspector.wiki_en_reference'; // we are sending them to enwiki anyway..
100713 url: 'https://' + langs[i] + '.wikipedia.org/wiki/' + title.replace(/ /g, '_')
100720 callback(null, result);
100725 var endpoint = 'https://en.wikipedia.org/w/api.php?';
100726 var serviceWikipedia = {
100727 init: function init() {},
100728 reset: function reset() {},
100729 search: function search(lang, query, callback) {
100731 if (callback) callback('No Query', []);
100736 var url = endpoint.replace('en', lang) + utilQsString({
100745 d3_json(url).then(function (result) {
100746 if (result && result.error) {
100747 throw new Error(result.error);
100748 } else if (!result || !result.query || !result.query.search) {
100749 throw new Error('No Results');
100753 var titles = result.query.search.map(function (d) {
100756 callback(null, titles);
100758 })["catch"](function (err) {
100759 if (callback) callback(err, []);
100762 suggestions: function suggestions(lang, query, callback) {
100764 if (callback) callback('', []);
100769 var url = endpoint.replace('en', lang) + utilQsString({
100777 d3_json(url).then(function (result) {
100778 if (result && result.error) {
100779 throw new Error(result.error);
100780 } else if (!result || result.length < 2) {
100781 throw new Error('No Results');
100784 if (callback) callback(null, result[1] || []);
100785 })["catch"](function (err) {
100786 if (callback) callback(err.message, []);
100789 translations: function translations(lang, title, callback) {
100791 if (callback) callback('No Title');
100795 var url = endpoint.replace('en', lang) + utilQsString({
100803 d3_json(url).then(function (result) {
100804 if (result && result.error) {
100805 throw new Error(result.error);
100806 } else if (!result || !result.query || !result.query.pages) {
100807 throw new Error('No Results');
100811 var list = result.query.pages[Object.keys(result.query.pages)[0]];
100814 if (list && list.langlinks) {
100815 list.langlinks.forEach(function (d) {
100816 translations[d.lang] = d['*'];
100820 callback(null, translations);
100822 })["catch"](function (err) {
100823 if (callback) callback(err.message);
100829 geocoder: serviceNominatim,
100830 keepRight: serviceKeepRight,
100831 improveOSM: serviceImproveOSM,
100833 mapillary: serviceMapillary,
100835 openstreetcam: serviceOpenstreetcam,
100837 osmWikibase: serviceOsmWikibase,
100838 maprules: serviceMapRules,
100839 streetside: serviceStreetside,
100840 taginfo: serviceTaginfo,
100841 vectorTile: serviceVectorTile,
100842 wikidata: serviceWikidata,
100843 wikipedia: serviceWikipedia
100846 function modeDragNote(context) {
100851 var edit = behaviorEdit(context);
100857 var _note; // most current note.. dragged note may have stale datum.
100860 function startNudge(d3_event, nudge) {
100861 if (_nudgeInterval) window.clearInterval(_nudgeInterval);
100862 _nudgeInterval = window.setInterval(function () {
100863 context.map().pan(nudge);
100864 doMove(d3_event, nudge);
100870 window.clearInterval(_nudgeInterval);
100875 function origin(note) {
100876 return context.projection(note.loc);
100879 function start(d3_event, note) {
100881 var osm = services.osm;
100884 // Get latest note from cache.. The marker may have a stale datum bound to it
100885 // and dragging it around can sometimes delete the users note comment.
100886 _note = osm.getNote(_note.id);
100889 context.surface().selectAll('.note-' + _note.id).classed('active', true);
100890 context.perform(actionNoop());
100892 context.selectedNoteID(_note.id);
100895 function move(d3_event, entity, point) {
100896 d3_event.stopPropagation();
100897 _lastLoc = context.projection.invert(point);
100899 var nudge = geoViewportEdge(point, context.map().dimensions());
100902 startNudge(d3_event, nudge);
100908 function doMove(d3_event, nudge) {
100909 nudge = nudge || [0, 0];
100910 var currPoint = d3_event && d3_event.point || context.projection(_lastLoc);
100911 var currMouse = geoVecSubtract(currPoint, nudge);
100912 var loc = context.projection.invert(currMouse);
100913 _note = _note.move(loc);
100914 var osm = services.osm;
100917 osm.replaceNote(_note); // update note cache
100920 context.replace(actionNoop()); // trigger redraw
100924 context.replace(actionNoop()); // trigger redraw
100926 context.selectedNoteID(_note.id).enter(modeSelectNote(context, _note.id));
100929 var drag = behaviorDrag().selector('.layer-touch.markers .target.note.new').surface(context.container().select('.main-map').node()).origin(origin).on('start', start).on('move', move).on('end', end);
100931 mode.enter = function () {
100935 mode.exit = function () {
100936 context.ui().sidebar.hover.cancel();
100937 context.uninstall(edit);
100938 context.surface().selectAll('.active').classed('active', false);
100946 function modeSelectData(context, selectedDatum) {
100951 var keybinding = utilKeybinding('select-data');
100952 var dataEditor = uiDataEditor(context);
100953 var behaviors = [behaviorBreathe(), behaviorHover(context), behaviorSelect(context), behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior]; // class the data as selected, or return to browse mode if the data is gone
100955 function selectData(d3_event, drawn) {
100956 var selection = context.surface().selectAll('.layer-mapdata .data' + selectedDatum.__featurehash__);
100958 if (selection.empty()) {
100959 // Return to browse mode if selected DOM elements have
100960 // disappeared because the user moved them out of view..
100961 var source = d3_event && d3_event.type === 'zoom' && d3_event.sourceEvent;
100963 if (drawn && source && (source.type === 'pointermove' || source.type === 'mousemove' || source.type === 'touchmove')) {
100964 context.enter(modeBrowse(context));
100967 selection.classed('selected', true);
100972 if (context.container().select('.combobox').size()) return;
100973 context.enter(modeBrowse(context));
100976 mode.zoomToSelected = function () {
100977 var extent = geoExtent(d3_geoBounds(selectedDatum));
100978 context.map().centerZoomEase(extent.center(), context.map().trimmedExtentZoom(extent));
100981 mode.enter = function () {
100982 behaviors.forEach(context.install);
100983 keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on('⎋', esc, true);
100984 select(document).call(keybinding);
100986 var sidebar = context.ui().sidebar;
100987 sidebar.show(dataEditor.datum(selectedDatum)); // expand the sidebar, avoid obscuring the data if needed
100989 var extent = geoExtent(d3_geoBounds(selectedDatum));
100990 sidebar.expand(sidebar.intersects(extent));
100991 context.map().on('drawn.select-data', selectData);
100994 mode.exit = function () {
100995 behaviors.forEach(context.uninstall);
100996 select(document).call(keybinding.unbind);
100997 context.surface().selectAll('.layer-mapdata .selected').classed('selected hover', false);
100998 context.map().on('drawn.select-data', null);
100999 context.ui().sidebar.hide();
101005 function behaviorSelect(context) {
101006 var _tolerancePx = 4; // see also behaviorDrag
101008 var _lastMouseEvent = null;
101010 var _downPointers = {};
101011 var _longPressTimeout = null;
101012 var _lastInteractionType = null; // the id of the down pointer that's enabling multiselection while down
101014 var _multiselectionPointerId = null; // use pointer events on supported platforms; fallback to mouse events
101016 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
101018 function keydown(d3_event) {
101019 if (d3_event.keyCode === 32) {
101020 // don't react to spacebar events during text input
101021 var activeNode = document.activeElement;
101022 if (activeNode && new Set(['INPUT', 'TEXTAREA']).has(activeNode.nodeName)) return;
101025 if (d3_event.keyCode === 93 || // context menu key
101026 d3_event.keyCode === 32) {
101028 d3_event.preventDefault();
101031 if (d3_event.repeat) return; // ignore repeated events for held keys
101032 // if any key is pressed the user is probably doing something other than long-pressing
101036 if (d3_event.shiftKey) {
101037 context.surface().classed('behavior-multiselect', true);
101040 if (d3_event.keyCode === 32) {
101042 if (!_downPointers.spacebar && _lastMouseEvent) {
101044 _longPressTimeout = window.setTimeout(didLongPress, 500, 'spacebar', 'spacebar');
101045 _downPointers.spacebar = {
101046 firstEvent: _lastMouseEvent,
101047 lastEvent: _lastMouseEvent
101053 function keyup(d3_event) {
101056 if (!d3_event.shiftKey) {
101057 context.surface().classed('behavior-multiselect', false);
101060 if (d3_event.keyCode === 93) {
101062 d3_event.preventDefault();
101063 _lastInteractionType = 'menukey';
101065 } else if (d3_event.keyCode === 32) {
101067 var pointer = _downPointers.spacebar;
101070 delete _downPointers.spacebar;
101071 if (pointer.done) return;
101072 d3_event.preventDefault();
101073 _lastInteractionType = 'spacebar';
101074 click(pointer.firstEvent, pointer.lastEvent, 'spacebar');
101079 function pointerdown(d3_event) {
101080 var id = (d3_event.pointerId || 'mouse').toString();
101082 if (d3_event.buttons && d3_event.buttons !== 1) return;
101083 context.ui().closeEditMenu();
101084 _longPressTimeout = window.setTimeout(didLongPress, 500, id, 'longdown-' + (d3_event.pointerType || 'mouse'));
101091 function didLongPress(id, interactionType) {
101092 var pointer = _downPointers[id];
101095 for (var i in _downPointers) {
101096 // don't allow this or any currently down pointer to trigger another click
101097 _downPointers[i].done = true;
101098 } // treat long presses like right-clicks
101101 _longPressTimeout = null;
101102 _lastInteractionType = interactionType;
101104 click(pointer.firstEvent, pointer.lastEvent, id);
101107 function pointermove(d3_event) {
101108 var id = (d3_event.pointerId || 'mouse').toString();
101110 if (_downPointers[id]) {
101111 _downPointers[id].lastEvent = d3_event;
101114 if (!d3_event.pointerType || d3_event.pointerType === 'mouse') {
101115 _lastMouseEvent = d3_event;
101117 if (_downPointers.spacebar) {
101118 _downPointers.spacebar.lastEvent = d3_event;
101123 function pointerup(d3_event) {
101124 var id = (d3_event.pointerId || 'mouse').toString();
101125 var pointer = _downPointers[id];
101127 delete _downPointers[id];
101129 if (_multiselectionPointerId === id) {
101130 _multiselectionPointerId = null;
101133 if (pointer.done) return;
101134 click(pointer.firstEvent, d3_event, id);
101137 function pointercancel(d3_event) {
101138 var id = (d3_event.pointerId || 'mouse').toString();
101139 if (!_downPointers[id]) return;
101140 delete _downPointers[id];
101142 if (_multiselectionPointerId === id) {
101143 _multiselectionPointerId = null;
101147 function contextmenu(d3_event) {
101148 d3_event.preventDefault();
101150 if (!+d3_event.clientX && !+d3_event.clientY) {
101152 d3_event.sourceEvent = _lastMouseEvent;
101157 _lastMouseEvent = d3_event;
101158 _lastInteractionType = 'rightclick';
101162 click(d3_event, d3_event);
101165 function click(firstEvent, lastEvent, pointerId) {
101167 var mapNode = context.container().select('.main-map').node(); // Use the `main-map` coordinate system since the surface and supersurface
101168 // are transformed when drag-panning.
101170 var pointGetter = utilFastMouse(mapNode);
101171 var p1 = pointGetter(firstEvent);
101172 var p2 = pointGetter(lastEvent);
101173 var dist = geoVecLength(p1, p2);
101175 if (dist > _tolerancePx || !mapContains(lastEvent)) {
101180 var targetDatum = lastEvent.target.__data__;
101181 var multiselectEntityId;
101183 if (!_multiselectionPointerId) {
101184 // If a different pointer than the one triggering this click is down on a
101185 // feature, treat this and all future clicks as multiselection until that
101187 var selectPointerInfo = pointerDownOnSelection(pointerId);
101189 if (selectPointerInfo) {
101190 _multiselectionPointerId = selectPointerInfo.pointerId; // if the other feature isn't selected yet, make sure we select it
101192 multiselectEntityId = !selectPointerInfo.selected && selectPointerInfo.entityId;
101193 _downPointers[selectPointerInfo.pointerId].done = true;
101195 } // support multiselect if data is already selected
101198 var isMultiselect = context.mode().id === 'select' && ( // and shift key is down
101199 lastEvent && lastEvent.shiftKey || // or we're lasso-selecting
101200 context.surface().select('.lasso').node() || // or a pointer is down over a selected feature
101201 _multiselectionPointerId && !multiselectEntityId);
101203 processClick(targetDatum, isMultiselect, p2, multiselectEntityId);
101205 function mapContains(event) {
101206 var rect = mapNode.getBoundingClientRect();
101207 return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
101210 function pointerDownOnSelection(skipPointerId) {
101211 var mode = context.mode();
101212 var selectedIDs = mode.id === 'select' ? mode.selectedIDs() : [];
101214 for (var pointerId in _downPointers) {
101215 if (pointerId === 'spacebar' || pointerId === skipPointerId) continue;
101216 var pointerInfo = _downPointers[pointerId];
101217 var p1 = pointGetter(pointerInfo.firstEvent);
101218 var p2 = pointGetter(pointerInfo.lastEvent);
101219 if (geoVecLength(p1, p2) > _tolerancePx) continue;
101220 var datum = pointerInfo.firstEvent.target.__data__;
101221 var entity = datum && datum.properties && datum.properties.entity || datum;
101223 if (context.graph().hasEntity(entity.id)) {
101227 selected: selectedIDs.indexOf(entity.id) !== -1
101236 function processClick(datum, isMultiselect, point, alsoSelectId) {
101237 var mode = context.mode();
101238 var showMenu = _showMenu;
101239 var interactionType = _lastInteractionType;
101240 var entity = datum && datum.properties && datum.properties.entity;
101241 if (entity) datum = entity;
101243 if (datum && datum.type === 'midpoint') {
101244 // treat targeting midpoints as if targeting the parent way
101245 datum = datum.parents[0];
101250 if (datum instanceof osmEntity) {
101252 var selectedIDs = context.selectedIDs();
101253 context.selectedNoteID(null);
101254 context.selectedErrorID(null);
101257 // don't change the selection if we're toggling the menu atop a multiselection
101258 if (!showMenu || selectedIDs.length <= 1 || selectedIDs.indexOf(datum.id) === -1) {
101259 if (alsoSelectId === datum.id) alsoSelectId = null;
101260 selectedIDs = (alsoSelectId ? [alsoSelectId] : []).concat([datum.id]); // always enter modeSelect even if the entity is already
101261 // selected since listeners may expect `context.enter` events,
101262 // e.g. in the walkthrough
101264 newMode = mode.id === 'select' ? mode.selectedIDs(selectedIDs) : modeSelect(context, selectedIDs).selectBehavior(behavior);
101265 context.enter(newMode);
101268 if (selectedIDs.indexOf(datum.id) !== -1) {
101269 // clicked entity is already in the selectedIDs list..
101271 // deselect clicked entity, then reenter select mode or return to browse mode..
101272 selectedIDs = selectedIDs.filter(function (id) {
101273 return id !== datum.id;
101275 newMode = selectedIDs.length ? mode.selectedIDs(selectedIDs) : modeBrowse(context).selectBehavior(behavior);
101276 context.enter(newMode);
101279 // clicked entity is not in the selected list, add it..
101280 selectedIDs = selectedIDs.concat([datum.id]);
101281 newMode = mode.selectedIDs(selectedIDs);
101282 context.enter(newMode);
101285 } else if (datum && datum.__featurehash__ && !isMultiselect) {
101286 // targeting custom data
101287 context.selectedNoteID(null).enter(modeSelectData(context, datum));
101288 } else if (datum instanceof osmNote && !isMultiselect) {
101290 context.selectedNoteID(datum.id).enter(modeSelectNote(context, datum.id));
101291 } else if (datum instanceof QAItem & !isMultiselect) {
101292 // targeting an external QA issue
101293 context.selectedErrorID(datum.id).enter(modeSelectError(context, datum.id, datum.service));
101296 context.selectedNoteID(null);
101297 context.selectedErrorID(null);
101299 if (!isMultiselect && mode.id !== 'browse') {
101300 context.enter(modeBrowse(context));
101304 context.ui().closeEditMenu(); // always request to show the edit menu in case the mode needs it
101306 if (showMenu) context.ui().showEditMenu(point, interactionType);
101310 function cancelLongPress() {
101311 if (_longPressTimeout) window.clearTimeout(_longPressTimeout);
101312 _longPressTimeout = null;
101315 function resetProperties() {
101318 _lastInteractionType = null; // don't reset _lastMouseEvent since it might still be useful
101321 function behavior(selection) {
101323 _lastMouseEvent = context.map().lastPointerEvent();
101324 select(window).on('keydown.select', keydown).on('keyup.select', keyup).on(_pointerPrefix + 'move.select', pointermove, true).on(_pointerPrefix + 'up.select', pointerup, true).on('pointercancel.select', pointercancel, true).on('contextmenu.select-window', function (d3_event) {
101325 // Edge and IE really like to show the contextmenu on the
101326 // menubar when user presses a keyboard menu button
101327 // even after we've already preventdefaulted the key event.
101330 if (+e.clientX === 0 && +e.clientY === 0) {
101331 d3_event.preventDefault();
101334 selection.on(_pointerPrefix + 'down.select', pointerdown).on('contextmenu.select', contextmenu);
101335 /*if (d3_event && d3_event.shiftKey) {
101337 .classed('behavior-multiselect', true);
101341 behavior.off = function (selection) {
101343 select(window).on('keydown.select', null).on('keyup.select', null).on('contextmenu.select-window', null).on(_pointerPrefix + 'move.select', null, true).on(_pointerPrefix + 'up.select', null, true).on('pointercancel.select', null, true);
101344 selection.on(_pointerPrefix + 'down.select', null).on('contextmenu.select', null);
101345 context.surface().classed('behavior-multiselect', false);
101351 function operationContinue(context, selectedIDs) {
101352 var _entities = selectedIDs.map(function (id) {
101353 return context.graph().entity(id);
101356 var _geometries = Object.assign({
101359 }, utilArrayGroupBy(_entities, function (entity) {
101360 return entity.geometry(context.graph());
101363 var _vertex = _geometries.vertex.length && _geometries.vertex[0];
101365 function candidateWays() {
101366 return _vertex ? context.graph().parentWays(_vertex).filter(function (parent) {
101367 return parent.geometry(context.graph()) === 'line' && !parent.isClosed() && parent.affix(_vertex.id) && (_geometries.line.length === 0 || _geometries.line[0] === parent);
101371 var _candidates = candidateWays();
101373 var operation = function operation() {
101374 var candidate = _candidates[0];
101375 context.enter(modeDrawLine(context, candidate.id, context.graph(), 'line', candidate.affix(_vertex.id), true));
101378 operation.relatedEntityIds = function () {
101379 return _candidates.length ? [_candidates[0].id] : [];
101382 operation.available = function () {
101383 return _geometries.vertex.length === 1 && _geometries.line.length <= 1 && !context.features().hasHiddenConnections(_vertex, context.graph());
101386 operation.disabled = function () {
101387 if (_candidates.length === 0) {
101389 } else if (_candidates.length > 1) {
101396 operation.tooltip = function () {
101397 var disable = operation.disabled();
101398 return disable ? _t('operations.continue.' + disable) : _t('operations.continue.description');
101401 operation.annotation = function () {
101402 return _t('operations.continue.annotation.line');
101405 operation.id = 'continue';
101406 operation.keys = [_t('operations.continue.key')];
101407 operation.title = _t('operations.continue.title');
101408 operation.behavior = behaviorOperation(context).which(operation);
101412 function operationCopy(context, selectedIDs) {
101413 function getFilteredIdsToCopy() {
101414 return selectedIDs.filter(function (selectedID) {
101415 var entity = context.graph().hasEntity(selectedID); // don't copy untagged vertices separately from ways
101417 return entity.hasInterestingTags() || entity.geometry(context.graph()) !== 'vertex';
101421 var operation = function operation() {
101422 var graph = context.graph();
101423 var selected = groupEntities(getFilteredIdsToCopy(), graph);
101429 for (i = 0; i < selected.relation.length; i++) {
101430 entity = selected.relation[i];
101432 if (!skip[entity.id] && entity.isComplete(graph)) {
101433 canCopy.push(entity.id);
101434 skip = getDescendants(entity.id, graph, skip);
101438 for (i = 0; i < selected.way.length; i++) {
101439 entity = selected.way[i];
101441 if (!skip[entity.id]) {
101442 canCopy.push(entity.id);
101443 skip = getDescendants(entity.id, graph, skip);
101447 for (i = 0; i < selected.node.length; i++) {
101448 entity = selected.node[i];
101450 if (!skip[entity.id]) {
101451 canCopy.push(entity.id);
101455 context.copyIDs(canCopy);
101457 if (_point && (canCopy.length !== 1 || graph.entity(canCopy[0]).type !== 'node')) {
101458 // store the anchor coordinates if copying more than a single node
101459 context.copyLonLat(context.projection.invert(_point));
101461 context.copyLonLat(null);
101465 function groupEntities(ids, graph) {
101466 var entities = ids.map(function (id) {
101467 return graph.entity(id);
101473 }, utilArrayGroupBy(entities, 'type'));
101476 function getDescendants(id, graph, descendants) {
101477 var entity = graph.entity(id);
101479 descendants = descendants || {};
101481 if (entity.type === 'relation') {
101482 children = entity.members.map(function (m) {
101485 } else if (entity.type === 'way') {
101486 children = entity.nodes;
101491 for (var i = 0; i < children.length; i++) {
101492 if (!descendants[children[i]]) {
101493 descendants[children[i]] = true;
101494 descendants = getDescendants(children[i], graph, descendants);
101501 operation.available = function () {
101502 return getFilteredIdsToCopy().length > 0;
101505 operation.disabled = function () {
101506 var extent = utilTotalExtent(getFilteredIdsToCopy(), context.graph());
101508 if (extent.percentContainedIn(context.map().extent()) < 0.8) {
101515 operation.availableForKeypress = function () {
101516 var selection = window.getSelection && window.getSelection(); // if the user has text selected then let them copy that, not the selected feature
101518 return !selection || !selection.toString();
101521 operation.tooltip = function () {
101522 var disable = operation.disabled();
101523 return disable ? _t('operations.copy.' + disable, {
101525 }) : _t('operations.copy.description', {
101530 operation.annotation = function () {
101531 return _t('operations.copy.annotation', {
101538 operation.point = function (val) {
101544 operation.keys = [uiCmd('⌘C')];
101545 operation.title = _t('operations.copy.title');
101546 operation.behavior = behaviorOperation(context).which(operation);
101550 function operationDisconnect(context, selectedIDs) {
101555 selectedIDs.forEach(function (id) {
101556 var entity = context.entity(id);
101558 if (entity.type === 'way') {
101560 } else if (entity.geometry(context.graph()) === 'vertex') {
101569 _annotationID = 'features';
101571 var _disconnectingVertexIds = [];
101572 var _disconnectingWayIds = [];
101574 if (_vertexIDs.length > 0) {
101575 // At the selected vertices, disconnect the selected ways, if any, else
101576 // disconnect all connected ways
101577 _disconnectingVertexIds = _vertexIDs;
101579 _vertexIDs.forEach(function (vertexID) {
101580 var action = actionDisconnect(vertexID);
101582 if (_wayIDs.length > 0) {
101583 var waysIDsForVertex = _wayIDs.filter(function (wayID) {
101584 var way = context.entity(wayID);
101585 return way.nodes.indexOf(vertexID) !== -1;
101588 action.limitWays(waysIDsForVertex);
101593 _disconnectingWayIds = _disconnectingWayIds.concat(context.graph().parentWays(context.graph().entity(vertexID)).map(function (d) {
101598 _disconnectingWayIds = utilArrayUniq(_disconnectingWayIds).filter(function (id) {
101599 return _wayIDs.indexOf(id) === -1;
101601 _descriptionID += _actions.length === 1 ? 'single_point.' : 'multiple_points.';
101603 if (_wayIDs.length === 1) {
101604 _descriptionID += 'single_way.' + context.graph().geometry(_wayIDs[0]);
101606 _descriptionID += _wayIDs.length === 0 ? 'no_ways' : 'multiple_ways';
101608 } else if (_wayIDs.length > 0) {
101609 // Disconnect the selected ways from each other, if they're connected,
101610 // else disconnect them from all connected ways
101611 var ways = _wayIDs.map(function (id) {
101612 return context.entity(id);
101615 var nodes = utilGetAllNodes(_wayIDs, context.graph());
101616 _coords = nodes.map(function (n) {
101618 }); // actions for connected nodes shared by at least two selected ways
101620 var sharedActions = [];
101621 var sharedNodes = []; // actions for connected nodes
101623 var unsharedActions = [];
101624 var unsharedNodes = [];
101625 nodes.forEach(function (node) {
101626 var action = actionDisconnect(node.id).limitWays(_wayIDs);
101628 if (action.disabled(context.graph()) !== 'not_connected') {
101634 if (way.nodes.indexOf(node.id) !== -1) {
101642 sharedActions.push(action);
101643 sharedNodes.push(node);
101645 unsharedActions.push(action);
101646 unsharedNodes.push(node);
101650 _descriptionID += 'no_points.';
101651 _descriptionID += _wayIDs.length === 1 ? 'single_way.' : 'multiple_ways.';
101653 if (sharedActions.length) {
101654 // if any nodes are shared, only disconnect the selected ways from each other
101655 _actions = sharedActions;
101656 _disconnectingVertexIds = sharedNodes.map(function (node) {
101659 _descriptionID += 'conjoined';
101660 _annotationID = 'from_each_other';
101662 // if no nodes are shared, disconnect the selected ways from all connected ways
101663 _actions = unsharedActions;
101664 _disconnectingVertexIds = unsharedNodes.map(function (node) {
101668 if (_wayIDs.length === 1) {
101669 _descriptionID += context.graph().geometry(_wayIDs[0]);
101671 _descriptionID += 'separate';
101676 var _extent = utilTotalExtent(_disconnectingVertexIds, context.graph());
101678 var operation = function operation() {
101679 context.perform(function (graph) {
101680 return _actions.reduce(function (graph, action) {
101683 }, operation.annotation());
101684 context.validator().validate();
101687 operation.relatedEntityIds = function () {
101688 if (_vertexIDs.length) {
101689 return _disconnectingWayIds;
101692 return _disconnectingVertexIds;
101695 operation.available = function () {
101696 if (_actions.length === 0) return false;
101697 if (_otherIDs.length !== 0) return false;
101698 if (_vertexIDs.length !== 0 && _wayIDs.length !== 0 && !_wayIDs.every(function (wayID) {
101699 return _vertexIDs.some(function (vertexID) {
101700 var way = context.entity(wayID);
101701 return way.nodes.indexOf(vertexID) !== -1;
101707 operation.disabled = function () {
101710 for (var actionIndex in _actions) {
101711 reason = _actions[actionIndex].disabled(context.graph());
101712 if (reason) return reason;
101715 if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
101716 return 'too_large.' + ((_vertexIDs.length ? _vertexIDs : _wayIDs).length === 1 ? 'single' : 'multiple');
101717 } else if (_coords && someMissing()) {
101718 return 'not_downloaded';
101719 } else if (selectedIDs.some(context.hasHiddenConnections)) {
101720 return 'connected_to_hidden';
101725 function someMissing() {
101726 if (context.inIntro()) return false;
101727 var osm = context.connection();
101730 var missing = _coords.filter(function (loc) {
101731 return !osm.isDataLoaded(loc);
101735 missing.forEach(function (loc) {
101736 context.loadTileAtLoc(loc);
101746 operation.tooltip = function () {
101747 var disable = operation.disabled();
101750 return _t('operations.disconnect.' + disable);
101753 return _t('operations.disconnect.description.' + _descriptionID);
101756 operation.annotation = function () {
101757 return _t('operations.disconnect.annotation.' + _annotationID);
101760 operation.id = 'disconnect';
101761 operation.keys = [_t('operations.disconnect.key')];
101762 operation.title = _t('operations.disconnect.title');
101763 operation.behavior = behaviorOperation(context).which(operation);
101767 function operationDowngrade(context, selectedIDs) {
101768 var _affectedFeatureCount = 0;
101770 var _downgradeType = downgradeTypeForEntityIDs(selectedIDs);
101772 var _multi = _affectedFeatureCount === 1 ? 'single' : 'multiple';
101774 function downgradeTypeForEntityIDs(entityIds) {
101776 _affectedFeatureCount = 0;
101778 for (var i in entityIds) {
101779 var entityID = entityIds[i];
101780 var type = downgradeTypeForEntityID(entityID);
101783 _affectedFeatureCount += 1;
101785 if (downgradeType && type !== downgradeType) {
101786 if (downgradeType !== 'generic' && type !== 'generic') {
101787 downgradeType = 'building_address';
101789 downgradeType = 'generic';
101800 function downgradeTypeForEntityID(entityID) {
101801 var graph = context.graph();
101802 var entity = graph.entity(entityID);
101803 var preset = _mainPresetIndex.match(entity, graph);
101804 if (!preset || preset.isFallback()) return null;
101806 if (entity.type === 'node' && preset.id !== 'address' && Object.keys(entity.tags).some(function (key) {
101807 return key.match(/^addr:.{1,}/);
101812 var geometry = entity.geometry(graph);
101814 if (geometry === 'area' && entity.tags.building && !preset.tags.building) {
101818 if (geometry === 'vertex' && Object.keys(entity.tags).length) {
101825 var buildingKeysToKeep = ['architect', 'building', 'height', 'layer', 'source', 'type', 'wheelchair'];
101826 var addressKeysToKeep = ['source'];
101828 var operation = function operation() {
101829 context.perform(function (graph) {
101830 for (var i in selectedIDs) {
101831 var entityID = selectedIDs[i];
101832 var type = downgradeTypeForEntityID(entityID);
101834 var tags = Object.assign({}, graph.entity(entityID).tags); // shallow copy
101836 for (var key in tags) {
101837 if (type === 'address' && addressKeysToKeep.indexOf(key) !== -1) continue;
101839 if (type === 'building') {
101840 if (buildingKeysToKeep.indexOf(key) !== -1 || key.match(/^building:.{1,}/) || key.match(/^roof:.{1,}/)) continue;
101843 if (type !== 'generic') {
101844 if (key.match(/^addr:.{1,}/) || key.match(/^source:.{1,}/)) continue;
101850 graph = actionChangeTags(entityID, tags)(graph);
101854 }, operation.annotation());
101855 context.validator().validate(); // refresh the select mode to enable the delete operation
101857 context.enter(modeSelect(context, selectedIDs));
101860 operation.available = function () {
101864 operation.disabled = function () {
101865 if (selectedIDs.some(hasWikidataTag)) {
101866 return 'has_wikidata_tag';
101871 function hasWikidataTag(id) {
101872 var entity = context.entity(id);
101873 return entity.tags.wikidata && entity.tags.wikidata.trim().length > 0;
101877 operation.tooltip = function () {
101878 var disable = operation.disabled();
101879 return disable ? _t('operations.downgrade.' + disable + '.' + _multi) : _t('operations.downgrade.description.' + _downgradeType);
101882 operation.annotation = function () {
101885 if (_downgradeType === 'building_address') {
101888 suffix = _downgradeType;
101891 return _t('operations.downgrade.annotation.' + suffix, {
101892 n: _affectedFeatureCount
101896 operation.id = 'downgrade';
101897 operation.keys = [uiCmd('⌫')];
101898 operation.title = _t('operations.downgrade.title');
101899 operation.behavior = behaviorOperation(context).which(operation);
101903 function operationExtract(context, selectedIDs) {
101904 var _amount = selectedIDs.length === 1 ? 'single' : 'multiple';
101906 var _geometries = utilArrayUniq(selectedIDs.map(function (entityID) {
101907 return context.graph().hasEntity(entityID) && context.graph().geometry(entityID);
101910 var _geometryID = _geometries.length === 1 ? _geometries[0] : 'feature';
101914 var _actions = selectedIDs.map(function (entityID) {
101915 var graph = context.graph();
101916 var entity = graph.hasEntity(entityID);
101917 if (!entity || !entity.hasInterestingTags()) return null;
101918 if (entity.type === 'node' && graph.parentWays(entity).length === 0) return null;
101920 if (entity.type !== 'node') {
101921 var preset = _mainPresetIndex.match(entity, graph); // only allow extraction from ways/relations if the preset supports points
101923 if (preset.geometry.indexOf('point') === -1) return null;
101926 _extent = _extent ? _extent.extend(entity.extent(graph)) : entity.extent(graph);
101927 return actionExtract(entityID, context.projection);
101930 var operation = function operation() {
101931 var combinedAction = function combinedAction(graph) {
101932 _actions.forEach(function (action) {
101939 context.perform(combinedAction, operation.annotation()); // do the extract
101941 var extractedNodeIDs = _actions.map(function (action) {
101942 return action.getExtractedNodeID();
101945 context.enter(modeSelect(context, extractedNodeIDs));
101948 operation.available = function () {
101949 return _actions.length && selectedIDs.length === _actions.length;
101952 operation.disabled = function () {
101953 if (_extent && _extent.percentContainedIn(context.map().extent()) < 0.8) {
101955 } else if (selectedIDs.some(function (entityID) {
101956 return context.graph().geometry(entityID) === 'vertex' && context.hasHiddenConnections(entityID);
101958 return 'connected_to_hidden';
101964 operation.tooltip = function () {
101965 var disableReason = operation.disabled();
101968 return _t('operations.extract.' + disableReason + '.' + _amount);
101970 return _t('operations.extract.description.' + _geometryID + '.' + _amount);
101974 operation.annotation = function () {
101975 return _t('operations.extract.annotation', {
101980 operation.id = 'extract';
101981 operation.keys = [_t('operations.extract.key')];
101982 operation.title = _t('operations.extract.title');
101983 operation.behavior = behaviorOperation(context).which(operation);
101987 function operationMerge(context, selectedIDs) {
101988 var _action = getAction();
101991 // prefer a non-disabled action first
101992 var join = actionJoin(selectedIDs);
101993 if (!join.disabled(context.graph())) return join;
101994 var merge = actionMerge(selectedIDs);
101995 if (!merge.disabled(context.graph())) return merge;
101996 var mergePolygon = actionMergePolygon(selectedIDs);
101997 if (!mergePolygon.disabled(context.graph())) return mergePolygon;
101998 var mergeNodes = actionMergeNodes(selectedIDs);
101999 if (!mergeNodes.disabled(context.graph())) return mergeNodes; // otherwise prefer an action with an interesting disabled reason
102001 if (join.disabled(context.graph()) !== 'not_eligible') return join;
102002 if (merge.disabled(context.graph()) !== 'not_eligible') return merge;
102003 if (mergePolygon.disabled(context.graph()) !== 'not_eligible') return mergePolygon;
102007 var operation = function operation() {
102008 if (operation.disabled()) return;
102009 context.perform(_action, operation.annotation());
102010 context.validator().validate();
102011 var resultIDs = selectedIDs.filter(context.hasEntity);
102013 if (resultIDs.length > 1) {
102014 var interestingIDs = resultIDs.filter(function (id) {
102015 return context.entity(id).hasInterestingTags();
102017 if (interestingIDs.length) resultIDs = interestingIDs;
102020 context.enter(modeSelect(context, resultIDs));
102023 operation.available = function () {
102024 return selectedIDs.length >= 2;
102027 operation.disabled = function () {
102028 var actionDisabled = _action.disabled(context.graph());
102030 if (actionDisabled) return actionDisabled;
102031 var osm = context.connection();
102033 if (osm && _action.resultingWayNodesLength && _action.resultingWayNodesLength(context.graph()) > osm.maxWayNodes()) {
102034 return 'too_many_vertices';
102040 operation.tooltip = function () {
102041 var disabled = operation.disabled();
102044 if (disabled === 'conflicting_relations') {
102045 return _t('operations.merge.conflicting_relations');
102048 if (disabled === 'restriction' || disabled === 'connectivity') {
102049 return _t('operations.merge.damage_relation', {
102050 relation: _mainPresetIndex.item('type/' + disabled).name()
102054 return _t('operations.merge.' + disabled);
102057 return _t('operations.merge.description');
102060 operation.annotation = function () {
102061 return _t('operations.merge.annotation', {
102066 operation.id = 'merge';
102067 operation.keys = [_t('operations.merge.key')];
102068 operation.title = _t('operations.merge.title');
102069 operation.behavior = behaviorOperation(context).which(operation);
102073 function operationPaste(context) {
102076 var operation = function operation() {
102077 if (!_pastePoint) return;
102078 var oldIDs = context.copyIDs();
102079 if (!oldIDs.length) return;
102080 var projection = context.projection;
102081 var extent = geoExtent();
102082 var oldGraph = context.copyGraph();
102084 var action = actionCopyEntities(oldIDs, oldGraph);
102085 context.perform(action);
102086 var copies = action.copies();
102087 var originals = new Set();
102088 Object.values(copies).forEach(function (entity) {
102089 originals.add(entity.id);
102092 for (var id in copies) {
102093 var oldEntity = oldGraph.entity(id);
102094 var newEntity = copies[id];
102096 extent._extend(oldEntity.extent(oldGraph)); // Exclude child nodes from newIDs if their parent way was also copied.
102099 var parents = context.graph().parentWays(newEntity);
102100 var parentCopied = parents.some(function (parent) {
102101 return originals.has(parent.id);
102105 newIDs.push(newEntity.id);
102107 } // Use the location of the copy operation to offset the paste location,
102108 // or else use the center of the pasted extent
102111 var copyPoint = context.copyLonLat() && projection(context.copyLonLat()) || projection(extent.center());
102112 var delta = geoVecSubtract(_pastePoint, copyPoint); // Move the pasted objects to be anchored at the paste location
102114 context.replace(actionMove(newIDs, delta, projection), operation.annotation());
102115 context.enter(modeSelect(context, newIDs));
102118 operation.point = function (val) {
102123 operation.available = function () {
102124 return context.mode().id === 'browse';
102127 operation.disabled = function () {
102128 return !context.copyIDs().length;
102131 operation.tooltip = function () {
102132 var oldGraph = context.copyGraph();
102133 var ids = context.copyIDs();
102136 return _t('operations.paste.nothing_copied');
102139 return _t('operations.paste.description', {
102140 feature: utilDisplayLabel(oldGraph.entity(ids[0]), oldGraph),
102145 operation.annotation = function () {
102146 var ids = context.copyIDs();
102147 return _t('operations.paste.annotation', {
102152 operation.id = 'paste';
102153 operation.keys = [uiCmd('⌘V')];
102154 operation.title = _t('operations.paste.title');
102158 function operationReverse(context, selectedIDs) {
102159 var operation = function operation() {
102160 context.perform(function combinedReverseAction(graph) {
102161 actions().forEach(function (action) {
102165 }, operation.annotation());
102166 context.validator().validate();
102169 function actions(situation) {
102170 return selectedIDs.map(function (entityID) {
102171 var entity = context.hasEntity(entityID);
102172 if (!entity) return null;
102174 if (situation === 'toolbar') {
102175 if (entity.type === 'way' && !entity.isOneWay() && !entity.isSided()) return null;
102178 var geometry = entity.geometry(context.graph());
102179 if (entity.type !== 'node' && geometry !== 'line') return null;
102180 var action = actionReverse(entityID);
102181 if (action.disabled(context.graph())) return null;
102186 function reverseTypeID() {
102188 var nodeActionCount = acts.filter(function (act) {
102189 var entity = context.hasEntity(act.entityID());
102190 return entity && entity.type === 'node';
102192 if (nodeActionCount === 0) return 'line';
102193 if (nodeActionCount === acts.length) return 'point';
102197 operation.available = function (situation) {
102198 return actions(situation).length > 0;
102201 operation.disabled = function () {
102205 operation.tooltip = function () {
102206 return _t('operations.reverse.description.' + reverseTypeID());
102209 operation.annotation = function () {
102211 return _t('operations.reverse.annotation.' + reverseTypeID(), {
102216 operation.id = 'reverse';
102217 operation.keys = [_t('operations.reverse.key')];
102218 operation.title = _t('operations.reverse.title');
102219 operation.behavior = behaviorOperation(context).which(operation);
102223 function operationSplit(context, selectedIDs) {
102224 var _vertexIds = selectedIDs.filter(function (id) {
102225 return context.graph().geometry(id) === 'vertex';
102228 var _selectedWayIds = selectedIDs.filter(function (id) {
102229 var entity = context.graph().hasEntity(id);
102230 return entity && entity.type === 'way';
102233 var _isAvailable = _vertexIds.length > 0 && _vertexIds.length + _selectedWayIds.length === selectedIDs.length;
102235 var _action = actionSplit(_vertexIds);
102238 var _geometry = 'feature';
102239 var _waysAmount = 'single';
102241 var _nodesAmount = _vertexIds.length === 1 ? 'single' : 'multiple';
102244 if (_selectedWayIds.length) _action.limitWays(_selectedWayIds);
102245 _ways = _action.ways(context.graph());
102248 _ways.forEach(function (way) {
102249 geometries[way.geometry(context.graph())] = true;
102252 if (Object.keys(geometries).length === 1) {
102253 _geometry = Object.keys(geometries)[0];
102256 _waysAmount = _ways.length === 1 ? 'single' : 'multiple';
102259 var operation = function operation() {
102260 var difference = context.perform(_action, operation.annotation()); // select both the nodes and the ways so the mapper can immediately disconnect them if desired
102262 var idsToSelect = _vertexIds.concat(difference.extantIDs().filter(function (id) {
102263 // filter out relations that may have had member additions
102264 return context.entity(id).type === 'way';
102267 context.enter(modeSelect(context, idsToSelect));
102270 operation.relatedEntityIds = function () {
102271 return _selectedWayIds.length ? [] : _ways.map(function (way) {
102276 operation.available = function () {
102280 operation.disabled = function () {
102281 var reason = _action.disabled(context.graph());
102285 } else if (selectedIDs.some(context.hasHiddenConnections)) {
102286 return 'connected_to_hidden';
102292 operation.tooltip = function () {
102293 var disable = operation.disabled();
102294 if (disable) return _t('operations.split.' + disable);
102295 return _t('operations.split.description.' + _geometry + '.' + _waysAmount + '.' + _nodesAmount + '_node');
102298 operation.annotation = function () {
102299 return _t('operations.split.annotation.' + _geometry, {
102304 operation.id = 'split';
102305 operation.keys = [_t('operations.split.key')];
102306 operation.title = _t('operations.split.title');
102307 operation.behavior = behaviorOperation(context).which(operation);
102311 function operationStraighten(context, selectedIDs) {
102312 var _wayIDs = selectedIDs.filter(function (id) {
102313 return id.charAt(0) === 'w';
102316 var _nodeIDs = selectedIDs.filter(function (id) {
102317 return id.charAt(0) === 'n';
102320 var _amount = (_wayIDs.length ? _wayIDs : _nodeIDs).length === 1 ? 'single' : 'multiple';
102322 var _nodes = utilGetAllNodes(selectedIDs, context.graph());
102324 var _coords = _nodes.map(function (n) {
102328 var _extent = utilTotalExtent(selectedIDs, context.graph());
102330 var _action = chooseAction();
102334 function chooseAction() {
102335 // straighten selected nodes
102336 if (_wayIDs.length === 0 && _nodeIDs.length > 2) {
102338 return actionStraightenNodes(_nodeIDs, context.projection); // straighten selected ways (possibly between range of 2 selected nodes)
102339 } else if (_wayIDs.length > 0 && (_nodeIDs.length === 0 || _nodeIDs.length === 2)) {
102343 for (var i = 0; i < selectedIDs.length; i++) {
102344 var entity = context.entity(selectedIDs[i]);
102346 if (entity.type === 'node') {
102348 } else if (entity.type !== 'way' || entity.isClosed()) {
102349 return null; // exit early, can't straighten these
102352 startNodeIDs.push(entity.first());
102353 endNodeIDs.push(entity.last());
102354 } // Remove duplicate end/startNodeIDs (duplicate nodes cannot be at the line end)
102357 startNodeIDs = startNodeIDs.filter(function (n) {
102358 return startNodeIDs.indexOf(n) === startNodeIDs.lastIndexOf(n);
102360 endNodeIDs = endNodeIDs.filter(function (n) {
102361 return endNodeIDs.indexOf(n) === endNodeIDs.lastIndexOf(n);
102362 }); // Ensure all ways are connected (i.e. only 2 unique endpoints/startpoints)
102364 if (utilArrayDifference(startNodeIDs, endNodeIDs).length + utilArrayDifference(endNodeIDs, startNodeIDs).length !== 2) return null; // Ensure path contains at least 3 unique nodes
102366 var wayNodeIDs = utilGetAllNodes(_wayIDs, context.graph()).map(function (node) {
102369 if (wayNodeIDs.length <= 2) return null; // If range of 2 selected nodes is supplied, ensure nodes lie on the selected path
102371 if (_nodeIDs.length === 2 && (wayNodeIDs.indexOf(_nodeIDs[0]) === -1 || wayNodeIDs.indexOf(_nodeIDs[1]) === -1)) return null;
102374 // If we're only straightenting between two points, we only need that extent visible
102375 _extent = utilTotalExtent(_nodeIDs, context.graph());
102379 return actionStraightenWay(selectedIDs, context.projection);
102387 context.perform(_action, operation.annotation());
102388 window.setTimeout(function () {
102389 context.validator().validate();
102390 }, 300); // after any transition
102393 operation.available = function () {
102394 return Boolean(_action);
102397 operation.disabled = function () {
102398 var reason = _action.disabled(context.graph());
102402 } else if (_extent.percentContainedIn(context.map().extent()) < 0.8) {
102404 } else if (someMissing()) {
102405 return 'not_downloaded';
102406 } else if (selectedIDs.some(context.hasHiddenConnections)) {
102407 return 'connected_to_hidden';
102412 function someMissing() {
102413 if (context.inIntro()) return false;
102414 var osm = context.connection();
102417 var missing = _coords.filter(function (loc) {
102418 return !osm.isDataLoaded(loc);
102422 missing.forEach(function (loc) {
102423 context.loadTileAtLoc(loc);
102433 operation.tooltip = function () {
102434 var disable = operation.disabled();
102435 return disable ? _t('operations.straighten.' + disable + '.' + _amount) : _t('operations.straighten.description.' + _geometry + (_wayIDs.length === 1 ? '' : 's'));
102438 operation.annotation = function () {
102439 return _t('operations.straighten.annotation.' + _geometry, {
102440 n: _wayIDs.length ? _wayIDs.length : _nodeIDs.length
102444 operation.id = 'straighten';
102445 operation.keys = [_t('operations.straighten.key')];
102446 operation.title = _t('operations.straighten.title');
102447 operation.behavior = behaviorOperation(context).which(operation);
102451 var Operations = /*#__PURE__*/Object.freeze({
102453 operationCircularize: operationCircularize,
102454 operationContinue: operationContinue,
102455 operationCopy: operationCopy,
102456 operationDelete: operationDelete,
102457 operationDisconnect: operationDisconnect,
102458 operationDowngrade: operationDowngrade,
102459 operationExtract: operationExtract,
102460 operationMerge: operationMerge,
102461 operationMove: operationMove,
102462 operationOrthogonalize: operationOrthogonalize,
102463 operationPaste: operationPaste,
102464 operationReflectShort: operationReflectShort,
102465 operationReflectLong: operationReflectLong,
102466 operationReverse: operationReverse,
102467 operationRotate: operationRotate,
102468 operationSplit: operationSplit,
102469 operationStraighten: operationStraighten
102472 function modeSelect(context, selectedIDs) {
102477 var keybinding = utilKeybinding('select');
102479 var _breatheBehavior = behaviorBreathe();
102481 var _modeDragNode = modeDragNode(context);
102487 var _newFeature = false;
102488 var _follow = false; // `_focusedParentWayId` is used when we visit a vertex with multiple
102489 // parents, and we want to remember which parent line we started on.
102491 var _focusedParentWayId;
102496 if (selectedIDs && selectedIDs.length === 1) {
102497 return context.hasEntity(selectedIDs[0]);
102501 function selectedEntities() {
102502 return selectedIDs.map(function (id) {
102503 return context.hasEntity(id);
102507 function checkSelectedIDs() {
102510 if (Array.isArray(selectedIDs)) {
102511 ids = selectedIDs.filter(function (id) {
102512 return context.hasEntity(id);
102517 context.enter(modeBrowse(context));
102519 } else if (selectedIDs.length > 1 && ids.length === 1 || selectedIDs.length === 1 && ids.length > 1) {
102520 // switch between single- and multi-select UI
102521 context.enter(modeSelect(context, ids));
102527 } // find the parent ways for nextVertex, previousVertex, and selectParent
102530 function parentWaysIdsOfSelection(onlyCommonParents) {
102531 var graph = context.graph();
102534 for (var i = 0; i < selectedIDs.length; i++) {
102535 var entity = context.hasEntity(selectedIDs[i]);
102537 if (!entity || entity.geometry(graph) !== 'vertex') {
102538 return []; // selection includes some non-vertices
102541 var currParents = graph.parentWays(entity).map(function (w) {
102550 parents = (onlyCommonParents ? utilArrayIntersection : utilArrayUnion)(parents, currParents);
102558 } // find the child nodes for selected ways
102561 function childNodeIdsOfSelection(onlyCommon) {
102562 var graph = context.graph();
102565 for (var i = 0; i < selectedIDs.length; i++) {
102566 var entity = context.hasEntity(selectedIDs[i]);
102568 if (!entity || !['area', 'line'].includes(entity.geometry(graph))) {
102569 return []; // selection includes non-area/non-line
102572 var currChilds = graph.childNodes(entity).map(function (node) {
102581 childs = (onlyCommon ? utilArrayIntersection : utilArrayUnion)(childs, currChilds);
102591 function checkFocusedParent() {
102592 if (_focusedParentWayId) {
102593 var parents = parentWaysIdsOfSelection(true);
102594 if (parents.indexOf(_focusedParentWayId) === -1) _focusedParentWayId = null;
102598 function parentWayIdForVertexNavigation() {
102599 var parentIds = parentWaysIdsOfSelection(true);
102601 if (_focusedParentWayId && parentIds.indexOf(_focusedParentWayId) !== -1) {
102602 // prefer the previously seen parent
102603 return _focusedParentWayId;
102606 return parentIds.length ? parentIds[0] : null;
102609 mode.selectedIDs = function (val) {
102610 if (!arguments.length) return selectedIDs;
102615 mode.zoomToSelected = function () {
102616 context.map().zoomToEase(selectedEntities());
102619 mode.newFeature = function (val) {
102620 if (!arguments.length) return _newFeature;
102625 mode.selectBehavior = function (val) {
102626 if (!arguments.length) return _selectBehavior;
102631 mode.follow = function (val) {
102632 if (!arguments.length) return _follow;
102637 function loadOperations() {
102638 _operations.forEach(function (operation) {
102639 if (operation.behavior) {
102640 context.uninstall(operation.behavior);
102644 _operations = Object.values(Operations).map(function (o) {
102645 return o(context, selectedIDs);
102646 }).filter(function (o) {
102647 return o.id !== 'delete' && o.id !== 'downgrade' && o.id !== 'copy';
102648 }).concat([// group copy/downgrade/delete operation together at the end of the list
102649 operationCopy(context, selectedIDs), operationDowngrade(context, selectedIDs), operationDelete(context, selectedIDs)]).filter(function (operation) {
102650 return operation.available();
102653 _operations.forEach(function (operation) {
102654 if (operation.behavior) {
102655 context.install(operation.behavior);
102657 }); // remove any displayed menu
102660 context.ui().closeEditMenu();
102663 mode.operations = function () {
102667 mode.enter = function () {
102668 if (!checkSelectedIDs()) return;
102669 context.features().forceVisible(selectedIDs);
102671 _modeDragNode.restoreSelectedIDs(selectedIDs);
102675 if (!_behaviors.length) {
102676 if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
102677 _behaviors = [behaviorPaste(context), _breatheBehavior, behaviorHover(context).on('hover', context.ui().sidebar.hoverModeSelect), _selectBehavior, behaviorLasso(context), _modeDragNode.behavior, modeDragNote(context).behavior];
102680 _behaviors.forEach(context.install);
102682 keybinding.on(_t('inspector.zoom_to.key'), mode.zoomToSelected).on(['[', 'pgup'], previousVertex).on([']', 'pgdown'], nextVertex).on(['{', uiCmd('⌘['), 'home'], firstVertex).on(['}', uiCmd('⌘]'), 'end'], lastVertex).on(uiCmd('⇧←'), nudgeSelection([-10, 0])).on(uiCmd('⇧↑'), nudgeSelection([0, -10])).on(uiCmd('⇧→'), nudgeSelection([10, 0])).on(uiCmd('⇧↓'), nudgeSelection([0, 10])).on(uiCmd('⇧⌥←'), nudgeSelection([-100, 0])).on(uiCmd('⇧⌥↑'), nudgeSelection([0, -100])).on(uiCmd('⇧⌥→'), nudgeSelection([100, 0])).on(uiCmd('⇧⌥↓'), nudgeSelection([0, 100])).on(utilKeybinding.plusKeys.map(function (key) {
102683 return uiCmd('⇧' + key);
102684 }), scaleSelection(1.05)).on(utilKeybinding.plusKeys.map(function (key) {
102685 return uiCmd('⇧⌥' + key);
102686 }), scaleSelection(Math.pow(1.05, 5))).on(utilKeybinding.minusKeys.map(function (key) {
102687 return uiCmd('⇧' + key);
102688 }), scaleSelection(1 / 1.05)).on(utilKeybinding.minusKeys.map(function (key) {
102689 return uiCmd('⇧⌥' + key);
102690 }), scaleSelection(1 / Math.pow(1.05, 5))).on(['\\', 'pause'], focusNextParent).on(uiCmd('⌘↑'), selectParent).on(uiCmd('⌘↓'), selectChild).on('⎋', esc, true);
102691 select(document).call(keybinding);
102692 context.ui().sidebar.select(selectedIDs, _newFeature);
102693 context.history().on('change.select', function () {
102694 loadOperations(); // reselect after change in case relation members were removed or added
102697 }).on('undone.select', checkSelectedIDs).on('redone.select', checkSelectedIDs);
102698 context.map().on('drawn.select', selectElements).on('crossEditableZoom.select', function () {
102701 _breatheBehavior.restartIfNeeded(context.surface());
102703 context.map().doubleUpHandler().on('doubleUp.modeSelect', didDoubleUp);
102707 var extent = geoExtent();
102708 var graph = context.graph();
102709 selectedIDs.forEach(function (id) {
102710 var entity = context.entity(id);
102712 extent._extend(entity.extent(graph));
102714 var loc = extent.center();
102715 context.map().centerEase(loc); // we could enter the mode multiple times, so reset follow for next time
102720 function nudgeSelection(delta) {
102722 // prevent nudging during low zoom selection
102723 if (!context.map().withinEditableZoom()) return;
102724 var moveOp = operationMove(context, selectedIDs);
102726 if (moveOp.disabled()) {
102727 context.ui().flash.duration(4000).iconName('#iD-operation-' + moveOp.id).iconClass('operation disabled').label(moveOp.tooltip)();
102729 context.perform(actionMove(selectedIDs, delta, context.projection), moveOp.annotation());
102730 context.validator().validate();
102735 function scaleSelection(factor) {
102737 // prevent scaling during low zoom selection
102738 if (!context.map().withinEditableZoom()) return;
102739 var nodes = utilGetAllNodes(selectedIDs, context.graph());
102740 var isUp = factor > 1; // can only scale if multiple nodes are selected
102742 if (nodes.length <= 1) return;
102743 var extent = utilTotalExtent(selectedIDs, context.graph()); // These disabled checks would normally be handled by an operation
102744 // object, but we don't want an actual scale operation at this point.
102746 function scalingDisabled() {
102749 } else if (extent.percentContainedIn(context.map().extent()) < 0.8) {
102751 } else if (someMissing() || selectedIDs.some(incompleteRelation)) {
102752 return 'not_downloaded';
102753 } else if (selectedIDs.some(context.hasHiddenConnections)) {
102754 return 'connected_to_hidden';
102760 if (isUp) return false;
102761 var dLon = Math.abs(extent[1][0] - extent[0][0]);
102762 var dLat = Math.abs(extent[1][1] - extent[0][1]);
102763 return dLon < geoMetersToLon(1, extent[1][1]) && dLat < geoMetersToLat(1);
102766 function someMissing() {
102767 if (context.inIntro()) return false;
102768 var osm = context.connection();
102771 var missing = nodes.filter(function (n) {
102772 return !osm.isDataLoaded(n.loc);
102776 missing.forEach(function (loc) {
102777 context.loadTileAtLoc(loc);
102786 function incompleteRelation(id) {
102787 var entity = context.entity(id);
102788 return entity.type === 'relation' && !entity.isComplete(context.graph());
102792 var disabled = scalingDisabled();
102795 var multi = selectedIDs.length === 1 ? 'single' : 'multiple';
102796 context.ui().flash.duration(4000).iconName('#iD-icon-no').iconClass('operation disabled').label(_t('operations.scale.' + disabled + '.' + multi))();
102798 var pivot = context.projection(extent.center());
102799 var annotation = _t('operations.scale.annotation.' + (isUp ? 'up' : 'down') + '.feature', {
102802 context.perform(actionScale(selectedIDs, pivot, factor, context.projection), annotation);
102803 context.validator().validate();
102808 function didDoubleUp(d3_event, loc) {
102809 if (!context.map().withinEditableZoom()) return;
102810 var target = select(d3_event.target);
102811 var datum = target.datum();
102812 var entity = datum && datum.properties && datum.properties.entity;
102815 if (entity instanceof osmWay && target.classed('target')) {
102816 var choice = geoChooseEdge(context.graph().childNodes(entity), loc, context.projection);
102817 var prev = entity.nodes[choice.index - 1];
102818 var next = entity.nodes[choice.index];
102819 context.perform(actionAddMidpoint({
102822 }, osmNode()), _t('operations.add.annotation.vertex'));
102823 context.validator().validate();
102824 } else if (entity.type === 'midpoint') {
102825 context.perform(actionAddMidpoint({
102828 }, osmNode()), _t('operations.add.annotation.vertex'));
102829 context.validator().validate();
102833 function selectElements() {
102834 if (!checkSelectedIDs()) return;
102835 var surface = context.surface();
102836 surface.selectAll('.selected-member').classed('selected-member', false);
102837 surface.selectAll('.selected').classed('selected', false);
102838 surface.selectAll('.related').classed('related', false); // reload `_focusedParentWayId` based on the current selection
102842 if (_focusedParentWayId) {
102843 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
102846 if (context.map().withinEditableZoom()) {
102847 // Apply selection styling if not in wide selection
102848 surface.selectAll(utilDeepMemberSelector(selectedIDs, context.graph(), true
102849 /* skipMultipolgonMembers */
102850 )).classed('selected-member', true);
102851 surface.selectAll(utilEntityOrDeepMemberSelector(selectedIDs, context.graph())).classed('selected', true);
102856 if (context.container().select('.combobox').size()) return;
102857 context.enter(modeBrowse(context));
102860 function firstVertex(d3_event) {
102861 d3_event.preventDefault();
102862 var entity = singular();
102863 var parentId = parentWayIdForVertexNavigation();
102866 if (entity && entity.type === 'way') {
102869 way = context.entity(parentId);
102872 _focusedParentWayId = way && way.id;
102875 context.enter(mode.selectedIDs([way.first()]).follow(true));
102879 function lastVertex(d3_event) {
102880 d3_event.preventDefault();
102881 var entity = singular();
102882 var parentId = parentWayIdForVertexNavigation();
102885 if (entity && entity.type === 'way') {
102888 way = context.entity(parentId);
102891 _focusedParentWayId = way && way.id;
102894 context.enter(mode.selectedIDs([way.last()]).follow(true));
102898 function previousVertex(d3_event) {
102899 d3_event.preventDefault();
102900 var parentId = parentWayIdForVertexNavigation();
102901 _focusedParentWayId = parentId;
102903 var way = context.entity(parentId);
102904 var length = way.nodes.length;
102905 var curr = way.nodes.indexOf(selectedIDs[0]);
102910 } else if (way.isClosed()) {
102915 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
102919 function nextVertex(d3_event) {
102920 d3_event.preventDefault();
102921 var parentId = parentWayIdForVertexNavigation();
102922 _focusedParentWayId = parentId;
102924 var way = context.entity(parentId);
102925 var length = way.nodes.length;
102926 var curr = way.nodes.indexOf(selectedIDs[0]);
102929 if (curr < length - 1) {
102931 } else if (way.isClosed()) {
102936 context.enter(mode.selectedIDs([way.nodes[index]]).follow(true));
102940 function focusNextParent(d3_event) {
102941 d3_event.preventDefault();
102942 var parents = parentWaysIdsOfSelection(true);
102943 if (!parents || parents.length < 2) return;
102944 var index = parents.indexOf(_focusedParentWayId);
102946 if (index < 0 || index > parents.length - 2) {
102947 _focusedParentWayId = parents[0];
102949 _focusedParentWayId = parents[index + 1];
102952 var surface = context.surface();
102953 surface.selectAll('.related').classed('related', false);
102955 if (_focusedParentWayId) {
102956 surface.selectAll(utilEntitySelector([_focusedParentWayId])).classed('related', true);
102960 function selectParent(d3_event) {
102961 d3_event.preventDefault();
102962 var currentSelectedIds = mode.selectedIDs();
102963 var parentIds = _focusedParentWayId ? [_focusedParentWayId] : parentWaysIdsOfSelection(false);
102964 if (!parentIds.length) return;
102965 context.enter(mode.selectedIDs(parentIds)); // set this after re-entering the selection since we normally want it cleared on exit
102967 _focusedVertexIds = currentSelectedIds;
102970 function selectChild(d3_event) {
102971 d3_event.preventDefault();
102972 var currentSelectedIds = mode.selectedIDs();
102973 var childIds = _focusedVertexIds ? _focusedVertexIds.filter(function (id) {
102974 return context.hasEntity(id);
102975 }) : childNodeIdsOfSelection(true);
102976 if (!childIds || !childIds.length) return;
102977 if (currentSelectedIds.length === 1) _focusedParentWayId = currentSelectedIds[0];
102978 context.enter(mode.selectedIDs(childIds));
102982 mode.exit = function () {
102983 // we could enter the mode multiple times but it's only new the first time
102985 _focusedVertexIds = null;
102987 _operations.forEach(function (operation) {
102988 if (operation.behavior) {
102989 context.uninstall(operation.behavior);
102995 _behaviors.forEach(context.uninstall);
102997 select(document).call(keybinding.unbind);
102998 context.ui().closeEditMenu();
102999 context.history().on('change.select', null).on('undone.select', null).on('redone.select', null);
103000 var surface = context.surface();
103001 surface.selectAll('.selected-member').classed('selected-member', false);
103002 surface.selectAll('.selected').classed('selected', false);
103003 surface.selectAll('.highlighted').classed('highlighted', false);
103004 surface.selectAll('.related').classed('related', false);
103005 context.map().on('drawn.select', null);
103006 context.ui().sidebar.hide();
103007 context.features().forceVisible([]);
103008 var entity = singular();
103010 if (_newFeature && entity && entity.type === 'relation' && // no tags
103011 Object.keys(entity.tags).length === 0 && // no parent relations
103012 context.graph().parentRelations(entity).length === 0 && ( // no members or one member with no role
103013 entity.members.length === 0 || entity.members.length === 1 && !entity.members[0].role)) {
103014 // the user added this relation but didn't edit it at all, so just delete it
103015 var deleteAction = actionDeleteRelation(entity.id, true
103016 /* don't delete untagged members */
103018 context.perform(deleteAction, _t('operations.delete.annotation.relation'));
103019 context.validator().validate();
103026 function uiLasso(context) {
103028 lasso.coordinates = [];
103030 function lasso(selection) {
103031 context.container().classed('lasso', true);
103032 group = selection.append('g').attr('class', 'lasso hide');
103033 polygon = group.append('path').attr('class', 'lasso-path');
103034 group.call(uiToggle(true));
103039 polygon.data([lasso.coordinates]).attr('d', function (d) {
103040 return 'M' + d.join(' L') + ' Z';
103045 lasso.extent = function () {
103046 return lasso.coordinates.reduce(function (extent, point) {
103047 return extent.extend(geoExtent(point));
103051 lasso.p = function (_) {
103052 if (!arguments.length) return lasso;
103053 lasso.coordinates.push(_);
103058 lasso.close = function () {
103060 group.call(uiToggle(false, function () {
103065 context.container().classed('lasso', false);
103071 function behaviorLasso(context) {
103072 // use pointer events on supported platforms; fallback to mouse events
103073 var _pointerPrefix = 'PointerEvent' in window ? 'pointer' : 'mouse';
103075 var behavior = function behavior(selection) {
103078 function pointerdown(d3_event) {
103079 var button = 0; // left
103081 if (d3_event.button === button && d3_event.shiftKey === true) {
103083 select(window).on(_pointerPrefix + 'move.lasso', pointermove).on(_pointerPrefix + 'up.lasso', pointerup);
103084 d3_event.stopPropagation();
103088 function pointermove() {
103090 lasso = uiLasso(context);
103091 context.surface().call(lasso);
103094 lasso.p(context.map().mouse());
103097 function normalize(a, b) {
103098 return [[Math.min(a[0], b[0]), Math.min(a[1], b[1])], [Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
103103 var graph = context.graph();
103106 if (context.map().editableDataEnabled(true
103108 ) && context.map().isInWideSelection()) {
103109 // only select from the visible nodes
103110 limitToNodes = new Set(utilGetAllNodes(context.selectedIDs(), graph));
103111 } else if (!context.map().editableDataEnabled()) {
103115 var bounds = lasso.extent().map(context.projection.invert);
103116 var extent = geoExtent(normalize(bounds[0], bounds[1]));
103117 var intersects = context.history().intersects(extent).filter(function (entity) {
103118 return entity.type === 'node' && (!limitToNodes || limitToNodes.has(entity)) && geoPointInPolygon(context.projection(entity.loc), lasso.coordinates) && !context.features().isHidden(entity, graph, entity.geometry(graph));
103119 }); // sort the lassoed nodes as best we can
103121 intersects.sort(function (node1, node2) {
103122 var parents1 = graph.parentWays(node1);
103123 var parents2 = graph.parentWays(node2);
103125 if (parents1.length && parents2.length) {
103126 // both nodes are vertices
103127 var sharedParents = utilArrayIntersection(parents1, parents2);
103129 if (sharedParents.length) {
103130 var sharedParentNodes = sharedParents[0].nodes; // vertices are members of the same way; sort them in their listed order
103132 return sharedParentNodes.indexOf(node1.id) - sharedParentNodes.indexOf(node2.id);
103134 // vertices do not share a way; group them by their respective parent ways
103135 return parseFloat(parents1[0].id.slice(1)) - parseFloat(parents2[0].id.slice(1));
103137 } else if (parents1.length || parents2.length) {
103138 // only one node is a vertex; sort standalone points before vertices
103139 return parents1.length - parents2.length;
103140 } // both nodes are standalone points; sort left to right
103143 return node1.loc[0] - node2.loc[0];
103145 return intersects.map(function (entity) {
103151 select(window).on(_pointerPrefix + 'move.lasso', null).on(_pointerPrefix + 'up.lasso', null);
103157 context.enter(modeSelect(context, ids));
103161 selection.on(_pointerPrefix + 'down.lasso', pointerdown);
103164 behavior.off = function (selection) {
103165 selection.on(_pointerPrefix + 'down.lasso', null);
103171 function modeBrowse(context) {
103175 title: _t('modes.browse.title'),
103176 description: _t('modes.browse.description')
103184 mode.selectBehavior = function (val) {
103185 if (!arguments.length) return _selectBehavior;
103190 mode.enter = function () {
103191 if (!_behaviors.length) {
103192 if (!_selectBehavior) _selectBehavior = behaviorSelect(context);
103193 _behaviors = [behaviorPaste(context), behaviorHover(context).on('hover', context.ui().sidebar.hover), _selectBehavior, behaviorLasso(context), modeDragNode(context).behavior, modeDragNote(context).behavior];
103196 _behaviors.forEach(context.install); // Get focus on the body.
103199 if (document.activeElement && document.activeElement.blur) {
103200 document.activeElement.blur();
103204 context.ui().sidebar.show(sidebar);
103206 context.ui().sidebar.select(null);
103210 mode.exit = function () {
103211 context.ui().sidebar.hover.cancel();
103213 _behaviors.forEach(context.uninstall);
103216 context.ui().sidebar.hide();
103220 mode.sidebar = function (_) {
103221 if (!arguments.length) return sidebar;
103226 mode.operations = function () {
103227 return [operationPaste(context)];
103233 function behaviorAddWay(context) {
103234 var dispatch = dispatch$8('start', 'startFromWay', 'startFromNode');
103235 var draw = behaviorDraw(context);
103237 function behavior(surface) {
103238 draw.on('click', function () {
103239 dispatch.apply('start', this, arguments);
103240 }).on('clickWay', function () {
103241 dispatch.apply('startFromWay', this, arguments);
103242 }).on('clickNode', function () {
103243 dispatch.apply('startFromNode', this, arguments);
103244 }).on('cancel', behavior.cancel).on('finish', behavior.cancel);
103245 context.map().dblclickZoomEnable(false);
103249 behavior.off = function (surface) {
103250 surface.call(draw.off);
103253 behavior.cancel = function () {
103254 window.setTimeout(function () {
103255 context.map().dblclickZoomEnable(true);
103257 context.enter(modeBrowse(context));
103260 return utilRebind(behavior, dispatch, 'on');
103263 function behaviorHash(context) {
103264 // cached window.location.hash
103265 var _cachedHash = null; // allowable latitude range
103267 var _latitudeLimit = 90 - 1e-8;
103269 function computedHashParameters() {
103270 var map = context.map();
103271 var center = map.center();
103273 var precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
103274 var oldParams = utilObjectOmit(utilStringQs(window.location.hash), ['comment', 'source', 'hashtags', 'walkthrough']);
103277 var selected = context.selectedIDs().filter(function (id) {
103278 return context.hasEntity(id);
103282 newParams.id = selected.join(',');
103285 newParams.map = zoom.toFixed(2) + '/' + center[1].toFixed(precision) + '/' + center[0].toFixed(precision);
103286 return Object.assign(oldParams, newParams);
103289 function computedHash() {
103290 return '#' + utilQsString(computedHashParameters(), true);
103293 function computedTitle(includeChangeCount) {
103294 var baseTitle = context.documentTitleBase() || 'iD';
103298 var selected = context.selectedIDs().filter(function (id) {
103299 return context.hasEntity(id);
103303 var firstLabel = utilDisplayLabel(context.entity(selected[0]), context.graph());
103305 if (selected.length > 1) {
103306 contextual = _t('title.labeled_and_more', {
103308 count: selected.length - 1
103311 contextual = firstLabel;
103317 if (includeChangeCount) {
103318 changeCount = context.history().difference().summary().length;
103321 titleID = contextual ? 'changes_context' : 'changes';
103326 return _t('title.format.' + titleID, {
103336 function updateTitle(includeChangeCount) {
103337 if (!context.setsDocumentTitle()) return;
103338 var newTitle = computedTitle(includeChangeCount);
103340 if (document.title !== newTitle) {
103341 document.title = newTitle;
103345 function updateHashIfNeeded() {
103346 if (context.inIntro()) return;
103347 var latestHash = computedHash();
103349 if (_cachedHash !== latestHash) {
103350 _cachedHash = latestHash; // Update the URL hash without affecting the browser navigation stack,
103351 // though unavoidably creating a browser history entry
103353 window.history.replaceState(null, computedTitle(false
103354 /* includeChangeCount */
103355 ), latestHash); // set the title we want displayed for the browser tab/window
103358 /* includeChangeCount */
103363 var _throttledUpdate = throttle(updateHashIfNeeded, 500);
103365 var _throttledUpdateTitle = throttle(function () {
103367 /* includeChangeCount */
103371 function hashchange() {
103372 // ignore spurious hashchange events
103373 if (window.location.hash === _cachedHash) return;
103374 _cachedHash = window.location.hash;
103375 var q = utilStringQs(_cachedHash);
103376 var mapArgs = (q.map || '').split('/').map(Number);
103378 if (mapArgs.length < 3 || mapArgs.some(isNaN)) {
103382 // don't update if the new hash already reflects the state of iD
103383 if (_cachedHash === computedHash()) return;
103384 var mode = context.mode();
103385 context.map().centerZoom([mapArgs[2], Math.min(_latitudeLimit, Math.max(-_latitudeLimit, mapArgs[1]))], mapArgs[0]);
103388 var ids = q.id.split(',').filter(function (id) {
103389 return context.hasEntity(id);
103392 if (ids.length && (mode.id === 'browse' || mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids))) {
103393 context.enter(modeSelect(context, ids));
103398 var center = context.map().center();
103399 var dist = geoSphericalDistance(center, [mapArgs[2], mapArgs[1]]);
103400 var maxdist = 500; // Don't allow the hash location to change too much while drawing
103401 // This can happen if the user accidentally hit the back button. #3996
103403 if (mode && mode.id.match(/^draw/) !== null && dist > maxdist) {
103404 context.enter(modeBrowse(context));
103411 context.map().on('move.behaviorHash', _throttledUpdate);
103412 context.history().on('change.behaviorHash', _throttledUpdateTitle);
103413 context.on('enter.behaviorHash', _throttledUpdate);
103414 select(window).on('hashchange.behaviorHash', hashchange);
103416 if (window.location.hash) {
103417 var q = utilStringQs(window.location.hash);
103420 //if (!context.history().hasRestorableChanges()) {
103421 // targeting specific features: download, select, and zoom to them
103422 context.zoomToEntity(q.id.split(',')[0], !q.map); //}
103425 if (q.walkthrough === 'true') {
103426 behavior.startWalkthrough = true;
103430 behavior.hadHash = true;
103438 behavior.off = function () {
103439 _throttledUpdate.cancel();
103441 _throttledUpdateTitle.cancel();
103443 context.map().on('move.behaviorHash', null);
103444 context.on('enter.behaviorHash', null);
103445 select(window).on('hashchange.behaviorHash', null);
103446 window.location.hash = '';
103452 // This is only done in testing because of the performance penalty.
103454 var debug = false; // Reexport just what our tests use, see #4379
103458 geoProjection: projection,
103459 polygonArea: d3_polygonArea,
103460 polygonCentroid: d3_polygonCentroid,
103466 var iD = /*#__PURE__*/Object.freeze({
103470 actionAddEntity: actionAddEntity,
103471 actionAddMember: actionAddMember,
103472 actionAddMidpoint: actionAddMidpoint,
103473 actionAddVertex: actionAddVertex,
103474 actionChangeMember: actionChangeMember,
103475 actionChangePreset: actionChangePreset,
103476 actionChangeTags: actionChangeTags,
103477 actionCircularize: actionCircularize,
103478 actionConnect: actionConnect,
103479 actionCopyEntities: actionCopyEntities,
103480 actionDeleteMember: actionDeleteMember,
103481 actionDeleteMultiple: actionDeleteMultiple,
103482 actionDeleteNode: actionDeleteNode,
103483 actionDeleteRelation: actionDeleteRelation,
103484 actionDeleteWay: actionDeleteWay,
103485 actionDiscardTags: actionDiscardTags,
103486 actionDisconnect: actionDisconnect,
103487 actionExtract: actionExtract,
103488 actionJoin: actionJoin,
103489 actionMerge: actionMerge,
103490 actionMergeNodes: actionMergeNodes,
103491 actionMergePolygon: actionMergePolygon,
103492 actionMergeRemoteChanges: actionMergeRemoteChanges,
103493 actionMove: actionMove,
103494 actionMoveMember: actionMoveMember,
103495 actionMoveNode: actionMoveNode,
103496 actionNoop: actionNoop,
103497 actionOrthogonalize: actionOrthogonalize,
103498 actionRestrictTurn: actionRestrictTurn,
103499 actionReverse: actionReverse,
103500 actionRevert: actionRevert,
103501 actionRotate: actionRotate,
103502 actionScale: actionScale,
103503 actionSplit: actionSplit,
103504 actionStraightenNodes: actionStraightenNodes,
103505 actionStraightenWay: actionStraightenWay,
103506 actionUnrestrictTurn: actionUnrestrictTurn,
103507 actionReflect: actionReflect,
103508 actionUpgradeTags: actionUpgradeTags,
103509 behaviorAddWay: behaviorAddWay,
103510 behaviorBreathe: behaviorBreathe,
103511 behaviorDrag: behaviorDrag,
103512 behaviorDrawWay: behaviorDrawWay,
103513 behaviorDraw: behaviorDraw,
103514 behaviorEdit: behaviorEdit,
103515 behaviorHash: behaviorHash,
103516 behaviorHover: behaviorHover,
103517 behaviorLasso: behaviorLasso,
103518 behaviorOperation: behaviorOperation,
103519 behaviorPaste: behaviorPaste,
103520 behaviorSelect: behaviorSelect,
103521 coreContext: coreContext,
103522 coreFileFetcher: coreFileFetcher,
103523 fileFetcher: _mainFileFetcher,
103524 coreDifference: coreDifference,
103526 coreHistory: coreHistory,
103527 coreLocalizer: coreLocalizer,
103529 localizer: _mainLocalizer,
103530 coreLocations: coreLocations,
103531 locationManager: _mainLocations,
103532 prefs: corePreferences,
103534 coreUploader: coreUploader,
103535 coreValidator: coreValidator,
103537 geoLatToMeters: geoLatToMeters,
103538 geoLonToMeters: geoLonToMeters,
103539 geoMetersToLat: geoMetersToLat,
103540 geoMetersToLon: geoMetersToLon,
103541 geoMetersToOffset: geoMetersToOffset,
103542 geoOffsetToMeters: geoOffsetToMeters,
103543 geoScaleToZoom: geoScaleToZoom,
103544 geoSphericalClosestNode: geoSphericalClosestNode,
103545 geoSphericalDistance: geoSphericalDistance,
103546 geoZoomToScale: geoZoomToScale,
103548 geoChooseEdge: geoChooseEdge,
103549 geoEdgeEqual: geoEdgeEqual,
103550 geoGetSmallestSurroundingRectangle: geoGetSmallestSurroundingRectangle,
103551 geoHasLineIntersections: geoHasLineIntersections,
103552 geoHasSelfIntersections: geoHasSelfIntersections,
103554 geoLineIntersection: geoLineIntersection,
103555 geoPathHasIntersections: geoPathHasIntersections,
103556 geoPathIntersections: geoPathIntersections,
103557 geoPathLength: geoPathLength,
103558 geoPointInPolygon: geoPointInPolygon,
103559 geoPolygonContainsPolygon: geoPolygonContainsPolygon,
103560 geoPolygonIntersectsPolygon: geoPolygonIntersectsPolygon,
103561 geoViewportEdge: geoViewportEdge,
103562 geoRawMercator: geoRawMercator,
103564 geoVecAngle: geoVecAngle,
103565 geoVecCross: geoVecCross,
103567 geoVecEqual: geoVecEqual,
103568 geoVecFloor: geoVecFloor,
103569 geoVecInterp: geoVecInterp,
103570 geoVecLength: geoVecLength,
103571 geoVecLengthSquare: geoVecLengthSquare,
103572 geoVecNormalize: geoVecNormalize,
103573 geoVecNormalizedDot: geoVecNormalizedDot,
103574 geoVecProject: geoVecProject,
103575 geoVecSubtract: geoVecSubtract,
103576 geoVecScale: geoVecScale,
103577 geoOrthoNormalizedDotProduct: geoOrthoNormalizedDotProduct,
103578 geoOrthoCalcScore: geoOrthoCalcScore,
103579 geoOrthoMaxOffsetAngle: geoOrthoMaxOffsetAngle,
103580 geoOrthoCanOrthogonalize: geoOrthoCanOrthogonalize,
103581 modeAddArea: modeAddArea,
103582 modeAddLine: modeAddLine,
103583 modeAddPoint: modeAddPoint,
103584 modeAddNote: modeAddNote,
103585 modeBrowse: modeBrowse,
103586 modeDragNode: modeDragNode,
103587 modeDragNote: modeDragNote,
103588 modeDrawArea: modeDrawArea,
103589 modeDrawLine: modeDrawLine,
103591 modeRotate: modeRotate,
103593 modeSelect: modeSelect,
103594 modeSelectData: modeSelectData,
103595 modeSelectError: modeSelectError,
103596 modeSelectNote: modeSelectNote,
103597 operationCircularize: operationCircularize,
103598 operationContinue: operationContinue,
103599 operationCopy: operationCopy,
103600 operationDelete: operationDelete,
103601 operationDisconnect: operationDisconnect,
103602 operationDowngrade: operationDowngrade,
103603 operationExtract: operationExtract,
103604 operationMerge: operationMerge,
103605 operationMove: operationMove,
103606 operationOrthogonalize: operationOrthogonalize,
103607 operationPaste: operationPaste,
103608 operationReflectShort: operationReflectShort,
103609 operationReflectLong: operationReflectLong,
103610 operationReverse: operationReverse,
103611 operationRotate: operationRotate,
103612 operationSplit: operationSplit,
103613 operationStraighten: operationStraighten,
103614 osmChangeset: osmChangeset,
103618 osmRelation: osmRelation,
103621 osmIntersection: osmIntersection,
103623 osmInferRestriction: osmInferRestriction,
103625 osmOldMultipolygonOuterMemberOfRelation: osmOldMultipolygonOuterMemberOfRelation,
103626 osmIsOldMultipolygonOuterMember: osmIsOldMultipolygonOuterMember,
103627 osmOldMultipolygonOuterMember: osmOldMultipolygonOuterMember,
103628 osmJoinWays: osmJoinWays,
103629 get osmAreaKeys () { return osmAreaKeys; },
103630 osmSetAreaKeys: osmSetAreaKeys,
103631 osmTagSuggestingArea: osmTagSuggestingArea,
103632 get osmPointTags () { return osmPointTags; },
103633 osmSetPointTags: osmSetPointTags,
103634 get osmVertexTags () { return osmVertexTags; },
103635 osmSetVertexTags: osmSetVertexTags,
103636 osmNodeGeometriesForTags: osmNodeGeometriesForTags,
103637 osmOneWayTags: osmOneWayTags,
103638 osmPavedTags: osmPavedTags,
103639 osmIsInterestingTag: osmIsInterestingTag,
103640 osmRoutableHighwayTagValues: osmRoutableHighwayTagValues,
103641 osmFlowingWaterwayTagValues: osmFlowingWaterwayTagValues,
103642 osmRailwayTrackTagValues: osmRailwayTrackTagValues,
103643 presetCategory: presetCategory,
103644 presetCollection: presetCollection,
103645 presetField: presetField,
103646 presetPreset: presetPreset,
103647 presetManager: _mainPresetIndex,
103648 presetIndex: presetIndex,
103649 rendererBackgroundSource: rendererBackgroundSource,
103650 rendererBackground: rendererBackground,
103651 rendererFeatures: rendererFeatures,
103652 rendererMap: rendererMap,
103653 rendererPhotos: rendererPhotos,
103654 rendererTileLayer: rendererTileLayer,
103656 serviceKeepRight: serviceKeepRight,
103657 serviceImproveOSM: serviceImproveOSM,
103658 serviceOsmose: serviceOsmose,
103659 serviceMapillary: serviceMapillary,
103660 serviceMapRules: serviceMapRules,
103661 serviceNominatim: serviceNominatim,
103662 serviceNsi: serviceNsi,
103663 serviceOpenstreetcam: serviceOpenstreetcam,
103664 serviceOsm: serviceOsm,
103665 serviceOsmWikibase: serviceOsmWikibase,
103666 serviceStreetside: serviceStreetside,
103667 serviceTaginfo: serviceTaginfo,
103668 serviceVectorTile: serviceVectorTile,
103669 serviceWikidata: serviceWikidata,
103670 serviceWikipedia: serviceWikipedia,
103675 svgKeepRight: svgKeepRight,
103677 svgGeolocate: svgGeolocate,
103681 svgMapillaryImages: svgMapillaryImages,
103682 svgMapillarySigns: svgMapillarySigns,
103683 svgMidpoints: svgMidpoints,
103685 svgMarkerSegments: svgMarkerSegments,
103686 svgOpenstreetcamImages: svgOpenstreetcamImages,
103688 svgPassiveVertex: svgPassiveVertex,
103690 svgPointTransform: svgPointTransform,
103692 svgRelationMemberTags: svgRelationMemberTags,
103693 svgSegmentWay: svgSegmentWay,
103694 svgStreetside: svgStreetside,
103695 svgTagClasses: svgTagClasses,
103696 svgTagPattern: svgTagPattern,
103699 svgVertices: svgVertices,
103700 uiFieldDefaultCheck: uiFieldCheck,
103701 uiFieldOnewayCheck: uiFieldCheck,
103702 uiFieldCheck: uiFieldCheck,
103703 uiFieldManyCombo: uiFieldCombo,
103704 uiFieldMultiCombo: uiFieldCombo,
103705 uiFieldNetworkCombo: uiFieldCombo,
103706 uiFieldSemiCombo: uiFieldCombo,
103707 uiFieldTypeCombo: uiFieldCombo,
103708 uiFieldCombo: uiFieldCombo,
103709 uiFieldUrl: uiFieldText,
103710 uiFieldIdentifier: uiFieldText,
103711 uiFieldNumber: uiFieldText,
103712 uiFieldTel: uiFieldText,
103713 uiFieldEmail: uiFieldText,
103714 uiFieldText: uiFieldText,
103715 uiFieldAccess: uiFieldAccess,
103716 uiFieldAddress: uiFieldAddress,
103717 uiFieldCycleway: uiFieldCycleway,
103718 uiFieldLanes: uiFieldLanes,
103719 uiFieldLocalized: uiFieldLocalized,
103720 uiFieldRoadheight: uiFieldRoadheight,
103721 uiFieldRoadspeed: uiFieldRoadspeed,
103722 uiFieldStructureRadio: uiFieldRadio,
103723 uiFieldRadio: uiFieldRadio,
103724 uiFieldRestrictions: uiFieldRestrictions,
103725 uiFieldTextarea: uiFieldTextarea,
103726 uiFieldWikidata: uiFieldWikidata,
103727 uiFieldWikipedia: uiFieldWikipedia,
103730 uiPanelBackground: uiPanelBackground,
103731 uiPanelHistory: uiPanelHistory,
103732 uiPanelLocation: uiPanelLocation,
103733 uiPanelMeasurement: uiPanelMeasurement,
103734 uiInfoPanels: uiInfoPanels,
103735 uiPaneBackground: uiPaneBackground,
103736 uiPaneHelp: uiPaneHelp,
103737 uiPaneIssues: uiPaneIssues,
103738 uiPaneMapData: uiPaneMapData,
103739 uiPanePreferences: uiPanePreferences,
103740 uiSectionBackgroundDisplayOptions: uiSectionBackgroundDisplayOptions,
103741 uiSectionBackgroundList: uiSectionBackgroundList,
103742 uiSectionBackgroundOffset: uiSectionBackgroundOffset,
103743 uiSectionChanges: uiSectionChanges,
103744 uiSectionDataLayers: uiSectionDataLayers,
103745 uiSectionEntityIssues: uiSectionEntityIssues,
103746 uiSectionFeatureType: uiSectionFeatureType,
103747 uiSectionMapFeatures: uiSectionMapFeatures,
103748 uiSectionMapStyleOptions: uiSectionMapStyleOptions,
103749 uiSectionOverlayList: uiSectionOverlayList,
103750 uiSectionPhotoOverlays: uiSectionPhotoOverlays,
103751 uiSectionPresetFields: uiSectionPresetFields,
103752 uiSectionPrivacy: uiSectionPrivacy,
103753 uiSectionRawMemberEditor: uiSectionRawMemberEditor,
103754 uiSectionRawMembershipEditor: uiSectionRawMembershipEditor,
103755 uiSectionRawTagEditor: uiSectionRawTagEditor,
103756 uiSectionSelectionList: uiSectionSelectionList,
103757 uiSectionValidationIssues: uiSectionValidationIssues,
103758 uiSectionValidationOptions: uiSectionValidationOptions,
103759 uiSectionValidationRules: uiSectionValidationRules,
103760 uiSectionValidationStatus: uiSectionValidationStatus,
103761 uiSettingsCustomBackground: uiSettingsCustomBackground,
103762 uiSettingsCustomData: uiSettingsCustomData,
103765 uiAttribution: uiAttribution,
103766 uiChangesetEditor: uiChangesetEditor,
103768 uiCombobox: uiCombobox,
103770 uiCommitWarnings: uiCommitWarnings,
103772 uiConflicts: uiConflicts,
103773 uiContributors: uiContributors,
103775 uiDataEditor: uiDataEditor,
103776 uiDataHeader: uiDataHeader,
103777 uiDisclosure: uiDisclosure,
103778 uiEditMenu: uiEditMenu,
103779 uiEntityEditor: uiEntityEditor,
103780 uiFeatureInfo: uiFeatureInfo,
103781 uiFeatureList: uiFeatureList,
103783 uiFieldHelp: uiFieldHelp,
103785 uiFormFields: uiFormFields,
103786 uiFullScreen: uiFullScreen,
103787 uiGeolocate: uiGeolocate,
103788 uiImproveOsmComments: uiImproveOsmComments,
103789 uiImproveOsmDetails: uiImproveOsmDetails,
103790 uiImproveOsmEditor: uiImproveOsmEditor,
103791 uiImproveOsmHeader: uiImproveOsmHeader,
103793 uiInspector: uiInspector,
103794 uiIssuesInfo: uiIssuesInfo,
103795 uiKeepRightDetails: uiKeepRightDetails,
103796 uiKeepRightEditor: uiKeepRightEditor,
103797 uiKeepRightHeader: uiKeepRightHeader,
103800 uiMapInMap: uiMapInMap,
103803 uiNoteComments: uiNoteComments,
103804 uiNoteEditor: uiNoteEditor,
103805 uiNoteHeader: uiNoteHeader,
103806 uiNoteReport: uiNoteReport,
103808 uiPresetIcon: uiPresetIcon,
103809 uiPresetList: uiPresetList,
103813 uiSourceSwitch: uiSourceSwitch,
103818 uiTagReference: uiTagReference,
103822 uiViewOnOSM: uiViewOnOSM,
103823 uiViewOnKeepRight: uiViewOnKeepRight,
103825 utilAesEncrypt: utilAesEncrypt,
103826 utilAesDecrypt: utilAesDecrypt,
103827 utilArrayChunk: utilArrayChunk,
103828 utilArrayDifference: utilArrayDifference,
103829 utilArrayFlatten: utilArrayFlatten,
103830 utilArrayGroupBy: utilArrayGroupBy,
103831 utilArrayIdentical: utilArrayIdentical,
103832 utilArrayIntersection: utilArrayIntersection,
103833 utilArrayUnion: utilArrayUnion,
103834 utilArrayUniq: utilArrayUniq,
103835 utilArrayUniqBy: utilArrayUniqBy,
103836 utilAsyncMap: utilAsyncMap,
103837 utilCleanTags: utilCleanTags,
103838 utilCombinedTags: utilCombinedTags,
103839 utilDeepMemberSelector: utilDeepMemberSelector,
103840 utilDetect: utilDetect,
103841 utilDisplayName: utilDisplayName,
103842 utilDisplayNameForPath: utilDisplayNameForPath,
103843 utilDisplayType: utilDisplayType,
103844 utilDisplayLabel: utilDisplayLabel,
103845 utilEntityRoot: utilEntityRoot,
103846 utilEditDistance: utilEditDistance,
103847 utilEntityAndDeepMemberIDs: utilEntityAndDeepMemberIDs,
103848 utilEntityOrMemberSelector: utilEntityOrMemberSelector,
103849 utilEntityOrDeepMemberSelector: utilEntityOrDeepMemberSelector,
103850 utilEntitySelector: utilEntitySelector,
103851 utilFastMouse: utilFastMouse,
103852 utilFunctor: utilFunctor,
103853 utilGetAllNodes: utilGetAllNodes,
103854 utilGetSetValue: utilGetSetValue,
103855 utilHashcode: utilHashcode,
103856 utilHighlightEntities: utilHighlightEntities,
103857 utilKeybinding: utilKeybinding,
103858 utilNoAuto: utilNoAuto,
103859 utilObjectOmit: utilObjectOmit,
103860 utilPrefixCSSProperty: utilPrefixCSSProperty,
103861 utilPrefixDOMProperty: utilPrefixDOMProperty,
103862 utilQsString: utilQsString,
103863 utilRebind: utilRebind,
103864 utilSafeClassName: utilSafeClassName,
103865 utilSetTransform: utilSetTransform,
103866 utilSessionMutex: utilSessionMutex,
103867 utilStringQs: utilStringQs,
103868 utilTagDiff: utilTagDiff,
103869 utilTagText: utilTagText,
103871 utilTotalExtent: utilTotalExtent,
103872 utilTriggerEvent: utilTriggerEvent,
103873 utilUnicodeCharsCount: utilUnicodeCharsCount,
103874 utilUnicodeCharsTruncated: utilUnicodeCharsTruncated,
103875 utilUniqueDomId: utilUniqueDomId,
103877 validationAlmostJunction: validationAlmostJunction,
103878 validationCloseNodes: validationCloseNodes,
103879 validationCrossingWays: validationCrossingWays,
103880 validationDisconnectedWay: validationDisconnectedWay,
103881 validationFormatting: validationFormatting,
103882 validationHelpRequest: validationHelpRequest,
103883 validationImpossibleOneway: validationImpossibleOneway,
103884 validationIncompatibleSource: validationIncompatibleSource,
103885 validationMaprules: validationMaprules,
103886 validationMismatchedGeometry: validationMismatchedGeometry,
103887 validationMissingRole: validationMissingRole,
103888 validationMissingTag: validationMissingTag,
103889 validationOutdatedTags: validationOutdatedTags,
103890 validationPrivateData: validationPrivateData,
103891 validationSuspiciousName: validationSuspiciousName,
103892 validationUnsquareWay: validationUnsquareWay
103895 window.requestIdleCallback = window.requestIdleCallback || function (cb) {
103896 var start = Date.now();
103897 return window.requestAnimationFrame(function () {
103900 timeRemaining: function timeRemaining() {
103901 return Math.max(0, 50 - (Date.now() - start));
103907 window.cancelIdleCallback = window.cancelIdleCallback || function (id) {
103908 window.cancelAnimationFrame(id);